Link

cmake

Vulkan λͺ…λ Ή μ‹€ν–‰

OpenGLμ΄λ‚˜ DirectX11 이전 λ²„μ „κ³ΌλŠ” 달리 Vulkanμ—μ„œλŠ” λͺ¨λ“  GPU λͺ…령이 μ»€λ§¨λ“œ 버퍼(Command buffer)λ₯Ό 톡해 μ „λ‹¬λ˜λ©°, 큐(Queue)λ₯Ό 톡해 μ‹€ν–‰λ©λ‹ˆλ‹€.

λͺ…령을 μ‹€ν–‰ν•˜λŠ” 일반적인 흐름은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.:

  • VkCommandPoolλ‘œλΆ€ν„° VkCommandBufferλ₯Ό ν• λ‹Ήν•©λ‹ˆλ‹€.
  • VkCmdXXXXX ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ λͺ…령을 μ»€λ§¨λ“œ 버퍼에 κΈ°λ‘ν•©λ‹ˆλ‹€.
  • VkQueue둜 μ»€λ§¨λ“œ 버퍼λ₯Ό μ œμΆœν•΄ λͺ…령을 싀행을 μ‹œμž‘ν•©λ‹ˆλ‹€.

같은 μ»€λ§¨λ“œ 버퍼λ₯Ό μ—¬λŸ¬ 번 μ œμΆœν•˜λŠ” 것도 κ°€λŠ₯ν•©λ‹ˆλ‹€. λ§Žμ€ νŠœν† λ¦¬μ–Όκ³Ό μ˜ˆμ œμ—μ„œλŠ” ν”νžˆ μ»€λ§¨λ“œ 버퍼λ₯Ό ν•œλ²ˆλ§Œ μž‘μ„±ν•˜μ—¬ λ Œλ”λ§ λ£¨ν”„μ—μ„œ λ§€ ν”„λ ˆμž„λ§ˆλ‹€ μ œμΆœν•˜λŠ” 방식을 μ‚¬μš©ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ 이 νŠœν† λ¦¬μ–Όμ—μ„œλŠ” λ§€ ν”„λ ˆμž„λ§ˆλ‹€ λͺ…령을 μž‘μ„±ν•  것이며, μ΄λŠ” μ‹€μ œ λ Œλ”λ§ μ—”μ§„μ˜ λ™μž‘ 방식과 더 μœ μ‚¬ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

Vulkanμ—μ„œ λͺ…령을 κΈ°λ‘ν•˜λŠ” 것은 μƒλŒ€μ μœΌλ‘œ λΉ„μš©μ΄ 적게 λ“­λ‹ˆλ‹€. 일반적으둜 λΉ„μš©μ΄ 많이 λ“œλŠ” μž‘μ—…μ€ VkQueueSubmit 호좜둜, 이 κ³Όμ •μ—μ„œ λ“œλΌμ΄λ²„κ°€ μ»€λ§¨λ“œ λ²„νΌμ˜ μœ νš¨μ„±μ„ κ²€μ‚¬ν•˜κ³  GPUμ—μ„œ μ‹€ν–‰ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

μ»€λ§¨λ“œ λ²„νΌμ—μ„œ 맀우 μ€‘μš”ν•œ 점은 λ³‘λ ¬λ‘œ 기둝할 수 μžˆλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. μ—¬λŸ¬ μ“°λ ˆλ“œμ—μ„œ μ„œλ‘œ λ‹€λ₯Έ μ»€λ§¨λ“œ 버퍼λ₯Ό μ•ˆμ „ν•˜κ²Œ 기둝할 수 μžˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό μœ„ν•΄ 각 μ“°λ ˆλ“œλŠ” μ΅œμ†Œν•œ ν•˜λ‚˜μ˜ VkCommandPoolκ³Ό ν•˜λ‚˜μ˜ VkCommandBufferλ₯Ό κ°€μ Έμ•Ό ν•˜λ©°, 각 μ“°λ ˆλ“œκ°€ μžμ‹ λ§Œμ˜ κ³ μœ ν•œ μ»€λ§¨λ“œ 버퍼와 μ»€λ§¨λ“œ ν’€(Command Pool)을 μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€. μ˜¬λ°”λ₯΄κ²Œ μ„€μ •ν•˜λ©΄ 각 μ“°λ ˆλ“œμ—μ„œ μ»€λ§¨λ“œ 버퍼λ₯Ό μ œμΆœν•  수 μžˆμŠ΅λ‹ˆλ‹€. vkQueueSubmit이 μ“°λ ˆλ“œ μ•ˆμ „(thread-safe)ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ—, ν•˜λ‚˜μ˜ νμ—λŠ” ν•œλ²ˆμ— ν•˜λ‚˜μ˜ μ“°λ ˆλ“œλ§Œ λͺ…령을 μ œμΆœν•  수 μžˆμŠ΅λ‹ˆλ‹€. λŒ€κ·œλͺ¨ μ—”μ§„μ—μ„œλŠ” ν”νžˆ λ°±κ·ΈλΌμš΄λ“œ μ“°λ ˆλ“œμ—μ„œ μ œμΆœμ„ μ²˜λ¦¬ν•˜λ©°, 메인 λ Œλ”λ§ 루프 μ“°λ ˆλ“œκ°€ 싀행될 수 μžˆλ„λ‘ ν•©λ‹ˆλ‹€.

VkQueue

Vulkanμ—μ„œμ˜ νλŠ” GPU의 μ‹€ν–‰ ν¬νŠΈμž…λ‹ˆλ‹€. λͺ¨λ“  GPUλŠ” μ‚¬μš©κ°€λŠ₯ν•œ μ—¬λŸ¬ 큐λ₯Ό κ°€μ§€λ©°, μ„œλ‘œ λ‹€λ₯Έ λͺ…령을 λ™μ‹œμ— μ‹€ν–‰ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. μ„œλ‘œ λ‹€λ₯Έ 큐에 제좜된 λͺ…령듀은 λ™μ‹œμ— 싀행될 수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” 메인 ν”„λ ˆμž„ 루프와 μ§μ ‘μ μœΌλ‘œ μ—°κ΄€λ˜μ§€ μ•ŠλŠ” λ°±κ·ΈλΌμš΄λ“œ μž‘μ—…μ„ μˆ˜ν–‰ν•  λ•Œ 맀우 μœ μš©ν•©λ‹ˆλ‹€. 이λ₯Ό μœ„ν•΄ λ°±κ·ΈλΌμš΄λ“œ μž‘μ—… μ „μš© VkQueueλ₯Ό μƒμ„±ν•˜μ—¬ 일반적인 λ Œλ”λ§ μž‘μ—…κ³Ό 뢄리할 수 μžˆμŠ΅λ‹ˆλ‹€.

Vulkan의 λͺ¨λ“  νλŠ” 큐 νŒ¨λ°€λ¦¬λ‘œλΆ€ν„° νŒŒμƒλ©λ‹ˆλ‹€. 큐 νŒ¨λ°€λ¦¬λŠ” νŠΉμ • μœ ν˜•μ˜ 큐 그룹이며, μ§€μ›ν•˜λŠ” λͺ…λ Ήμ˜ μ’…λ₯˜κ°€ 각기 λ‹€λ¦…λ‹ˆλ‹€.

GPUλŠ” 각기 λ‹€λ₯Έ 큐 νŒ¨λ°€λ¦¬λ₯Ό μ§€μ›ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ NVIDIA GT 750TI의 경우, 이 λ§ν¬μ—μ„œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€. 이 GPUμ—λŠ” 2개의 큐 νŒ¨λ°€λ¦¬κ°€ 있으며, ν•˜λ‚˜λŠ” λͺ¨λ“  κΈ°λŠ₯을 μ§€μ›ν•˜λŠ” 16개의 큐둜 이루어져 있으며, λ‹€λ₯Έ ν•˜λ‚˜λŠ” 전솑(Transfer)λ§Œμ„ μ§€μ›ν•˜λŠ” 1개의 큐둜 이루어진 큐 νŒ¨λ°€λ¦¬κ°€ μžˆμŠ΅λ‹ˆλ‹€. 반면, κ³ μ„±λŠ₯ AMD GPUλŠ” μ—¬κΈ°λ₯Ό μ°Έκ³ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.이 GPUμ—λŠ” 5개의 큐 νŒ¨λ°€λ¦¬κ°€ 있으며, 각 μœ ν˜•λ³„λ‘œ μ΅œλŒ€ 2개의 큐만 μ‘΄μž¬ν•©λ‹ˆλ‹€. 1개의 νλŠ” λͺ¨λ“  κΈ°λŠ₯을 μ§€μ›ν•˜κ³ , 계산(Compute) 및 전솑(Transfer) μž‘μ—…μ„ μ§€μ›ν•˜λŠ” 2개의 큐, 2개의 전솑 μ „μš© 큐, 2개의 ν‘œμ‹œ(Present) μ „μš© 큐가 μžˆμŠ΅λ‹ˆλ‹€. 이처럼, 각 GPUκ°€ μ§€μ›ν•˜λŠ” 큐 νŒ¨λ°€λ¦¬λŠ” μƒλ‹Ήνžˆ λ‹€λ₯Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

λŒ€λΆ€λΆ„μ˜ μ—”μ§„μ—μ„œλŠ” 3개의 큐 νŒ¨λ°€λ¦¬λ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μΌλ°˜μ μž…λ‹ˆλ‹€. ν•˜λ‚˜λŠ” ν”„λ ˆμž„μ„ κ·Έλ¦¬λŠ” 데 μ‚¬μš©ν•˜κ³ , λ‹€λ₯Έ ν•˜λ‚˜λŠ” 비동기 계산(compute), 그리고 λ‹€λ₯Έ ν•˜λ‚˜λŠ” 데이터 μ „μ†‘μž…λ‹ˆλ‹€. 이 νŠœν† λ¦¬μ–Όμ—μ„œλŠ” λ‹¨μˆœν™”λ₯Ό μœ„ν•΄ ν•˜λ‚˜μ˜ νμ—μ„œ λͺ¨λ“  λͺ…령을 μ‹€ν–‰ν•˜κ² μŠ΅λ‹ˆλ‹€.

VkCommandPool

VkCommandPool은 VkDeviceλ₯Ό 기반으둜 μƒμ„±λ˜λ©°, ν•΄λ‹Ή μ»€λ§¨λ“œ 풀이 λͺ…령을 생성할 큐 νŒ¨λ°€λ¦¬μ˜ μΈλ±μŠ€κ°€ ν•„μš”ν•©λ‹ˆλ‹€.

VkCommandPool을 VkCommandBuffer의 할당기라고 생각할 수 μžˆμŠ΅λ‹ˆλ‹€. ν•˜λ‚˜μ˜ ν’€μ—μ„œ μ›ν•˜λŠ” 만큼 VkCommandBufferλ₯Ό ν• λ‹Ήν•  수 μžˆμ§€λ§Œ, ν•œ λ²ˆμ— ν•˜λ‚˜μ˜ μ“°λ ˆλ“œλ§Œ λͺ…령을 기둝할 수 μžˆμŠ΅λ‹ˆλ‹€. λ§Œμ•½ λ©€ν‹°μ“°λ ˆλ“œ ν™˜κ²½μ—μ„œ λͺ…령을 κΈ°λ‘ν•˜κ³ μž ν•œλ‹€λ©΄ 좔가적인 VkCommandPool 객체가 ν•„μš”ν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ 이유둜, ν•΄λ‹Ή μ»€λ§¨λ“œ ν’€κ³Ό 쌍으둜 ꡬ성할 κ²ƒμž…λ‹ˆλ‹€.

VkCommandBuffer

GPU의 λͺ¨λ“  λͺ…령은 VkCommandBuffer에 κΈ°λ‘λ©λ‹ˆλ‹€. GPU의 μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” λͺ¨λ“  ν•¨μˆ˜λŠ” μ»€λ§¨λ“œ 버퍼가 VkQueueSubmit을 톡해 GPU둜 제좜될 λ•ŒκΉŒμ§€ μ‹€ν–‰λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μ»€λ§¨λ“œ λ²„νΌλŠ” μ€€λΉ„(Ready) μƒνƒœμ—μ„œλΆ€ν„° μ‹œμž‘ν•©λ‹ˆλ‹€. μ€€λΉ„ μƒνƒœμ—μ„œλŠ” vkBeginCommandBuffer()λ₯Ό ν˜ΈμΆœν•΄ 기둝(Recording) μƒνƒœλ‘œ λ³€κ²½ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이 μƒνƒœμ—μ„œ vkCmdXXXXXν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•΄ λͺ…령을 기둝할 수 μžˆμŠ΅λ‹ˆλ‹€. λͺ¨λ“  λͺ…령을 κΈ°λ‘ν•˜κ³  λ‚˜λ©΄ vkEndCommandBuffer()λ₯Ό ν˜ΈμΆœν•˜μ—¬ μ‹€ν–‰κ°€λŠ₯ν•œ(Executable) μƒνƒœλ‘œ λ³€κ²½ν•˜λ©΄ ν•΄λ‹Ή μ»€λ§¨λ“œ 버퍼λ₯Ό GPU에 μ œμΆœν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ»€λ§¨λ“œ 버퍼λ₯Ό μ œμΆœν•˜λ €λ©΄ μ œμΆœν•  λͺ…λ Ήκ³Ό 큐λ₯Ό μ§€μ •ν•˜μ—¬ vkQueueSubmit()λ₯Ό ν˜ΈμΆœν•©λ‹ˆλ‹€. λ˜ν•œ, vkQueueSubmit은 μ—¬λŸ¬ 개의 μ»€λ§¨λ“œ 버퍼λ₯Ό ν•œ λ²ˆμ— μ œμΆœν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. μ œμΆœν•œ λͺ¨λ“  μ»€λ§¨λ“œ λ²„νΌλŠ” 보λ₯˜(Pending) μƒνƒœλ‘œ λ³€ν™˜λ©λ‹ˆλ‹€.

μ»€λ§¨λ“œ 버퍼가 제좜되면 μ—¬μ „νžˆ β€œμœ νš¨(alive)β€ν•˜λ©° GPUμ—μ„œ 처리되고 μžˆμŠ΅λ‹ˆλ‹€. 이 μ‹œμ μ—μ„œλŠ” μ»€λ§¨λ“œ 버퍼λ₯Ό λ¦¬μ…‹ν•˜λŠ” 것이 μ•ˆμ „ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ»€λ§¨λ“œ 버퍼λ₯Ό μž¬μ„€μ •ν•˜κ³  μž¬μ‚¬μš© ν•˜κΈ° 전에, GPUκ°€ ν•΄λ‹Ή μ»€λ§¨λ“œ λ²„νΌμ˜ λͺ¨λ“  λͺ…령을 μ™„λ£Œν–ˆλŠ” μ§€ 확인해야 ν•©λ‹ˆλ‹€.

μ»€λ§¨λ“œ 버퍼λ₯Ό λ¦¬μ…‹ν•˜κΈ° μœ„ν•΄μ„œ vkResetCommandBuffer()λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

μ»€λ§¨λ“œ 버퍼가 싀행쀑인 λ™μ•ˆ λ‹€μŒ ν”„λ ˆμž„μ„ 계속 그릴 수 μžˆλ„λ‘ 더블 버퍼링을 μˆ˜ν–‰ν•  κ²ƒμž…λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ GPUκ°€ ν•œ λ²„νΌμ—μ„œ λ Œλ”λ§ 및 처리λ₯Ό μˆ˜ν–‰ν•˜λŠ” λ™μ•ˆ, λ‹€λ₯Έ λ²„νΌμ—μ„œ λͺ…령을 기둝할 수 μžˆμŠ΅λ‹ˆλ‹€.

μ»€λ§¨λ“œ λ²„νΌμ˜ 생λͺ…주기에 λŒ€ν•œ 더 μžμ„Έν•œ μ •λ³΄λŠ” λ‹€μŒ Vulkan μ‚¬μ–‘μ˜ κ΄€λ ¨ 글을 μ°Έκ³ ν•˜μ„Έμš”.

https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap6.html#commandbuffers-lifecycle.

Next: Setting up Vulkan commands