FrameData
๊ตฌ์กฐ์ฒด๋ฅผ vk_engine.h
์ ์์ฑํ๊ฒ ์ต๋๋ค. ์ด ๊ตฌ์กฐ์ฒด๋ ์ฃผ์ด์ง ํ๋ ์์ ๋ ๋๋งํ๋ ๋ฐ ํ์ํ ๊ตฌ์กฐ์ฒด์ ๋ช
๋ น์ ์ ์ฅํ๊ฒ ๋ฉ๋๋ค. ๋๋ธ ๋ฒํผ๋ง์ ์ฌ์ฉํ ๊ฒ์ด๋ฏ๋ก, GPU๊ฐ ํ์ชฝ ๋ฒํผ์์ ๋ช
๋ น์ ์คํํ๋ ๋์ ๋ค๋ฅธ ๋ฒํผ์์ ๋ช
๋ น์ ๊ธฐ๋กํ ์ ์๋๋ก ์ค๊ณํ ๊ฒ์
๋๋ค.
struct FrameData {
VkCommandPool _commandPool;
VkCommandBuffer _mainCommandBuffer;
};
constexpr unsigned int FRAME_OVERLAP = 2;
์ด๋ฅผ ํ๋ฅผ ์ ์ฅํ ๋ฉค๋ฒ ๋ณ์์ ํจ๊ป VulkanEngine
ํด๋์ค์ ์ถ๊ฐํด์ค๋๋ค.
class VulkanEngine{
public:
FrameData _frames[FRAME_OVERLAP];
FrameData& get_current_frame() { return _frames[_frameNumber % FRAME_OVERLAP]; };
VkQueue _graphicsQueue;
uint32_t _graphicsQueueFamily;
}
์ด๊ธฐํ ๋ก์ง ์ธ๋ถ์์ _frames
๋ฐฐ์ด์ ์ง์ ์ ์ผ๋ก ์ ๊ทผํ์ง๋ ์์ ๊ฒ์
๋๋ค. ๋ฐ๋ผ์ _frameNumber
๋ฉค๋ฒ๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น ๋ฐฐ์ด์ ์ฐธ์กฐํ๋ getter๋ฅผ ์ถ๊ฐํ๊ฒ ์ต๋๋ค. ์ด๋ฅผ ํตํด ๋ ๊ฐ์ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ฒ๊ฐ์ ๊ฐ๋ฉฐ ์ฌ์ฉํ ์ ์์ต๋๋ค.
ํ ๊ฐ์ ธ์ค๊ธฐ
์ด์ ์ ํจํ ํ ํจ๋ฐ๋ฆฌ๋ฅผ ์ฐพ์ ๊ทธ๋ก๋ถํฐ ํ๋ฅผ ์์ฑํด์ผ ํฉ๋๋ค. ๋ชจ๋ ์ข ๋ฅ์ ๋ช ๋ น์ ์คํํ ์ ์๋ ํ๋ฅผ ์์ฑํ์ฌ ์์ง ์ ๋ฐ์์ ํ์ฉํ ๊ฒ์ ๋๋ค.
๋คํํ VkBootstrap ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด ํ์ ํ ํจ๋ฐ๋ฆฌ๋ฅผ ์ง์ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
init_vulkan()
ํจ์์ ๋ง์ง๋ง ๋ถ๋ถ์ผ๋ก ๊ฐ๋ด
์๋ค.
๋งจ ๋ง์ง๋ง์ ๋ค์ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
void VulkanEngine::init_vulkan(){
// ---- other code, initializing vulkan device ----
// use vkbootstrap to get a Graphics queue
_graphicsQueue = vkbDevice.get_queue(vkb::QueueType::graphics).value();
_graphicsQueueFamily = vkbDevice.get_queue_index(vkb::QueueType::graphics).value();
}
vkbootstrap์ ํตํด ๊ทธ๋ํฝ์ค ํ์ ํ ํจ๋ฐ๋ฆฌ๋ฅผ ์์ฒญํฉ๋๋ค.
์ปค๋งจ๋ ๊ตฌ์กฐ์ฒด ์์ฑํ๊ธฐ
์ปค๋งจ๋ ํ์ ์์ฑํ๊ธฐ ์ํด init_commands()
ํจ์ ๋ด๋ถ์ ์ด์ ๊ณผ๋ ๋ค๋ฅธ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค. ์ด๋ฒ์๋ VkBootstrap ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ง ์์ ๊ฒ์ด๋ฉฐ, ์ง์ Vulkan ๋ช
๋ น์ ํธ์ถํ๊ฒ ์ต๋๋ค.
void VulkanEngine::init_commands()
{
//create a command pool for commands submitted to the graphics queue.
//we also want the pool to allow for resetting of individual command buffers
VkCommandPoolCreateInfo commandPoolInfo = {};
commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
commandPoolInfo.pNext = nullptr;
commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
commandPoolInfo.queueFamilyIndex = _graphicsQueueFamily;
for (int i = 0; i < FRAME_OVERLAP; i++) {
VK_CHECK(vkCreateCommandPool(_device, &commandPoolInfo, nullptr, &_frames[i]._commandPool));
// allocate the default command buffer that we will use for rendering
VkCommandBufferAllocateInfo cmdAllocInfo = {};
cmdAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cmdAllocInfo.pNext = nullptr;
cmdAllocInfo.commandPool = _frames[i]._commandPool;
cmdAllocInfo.commandBufferCount = 1;
cmdAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
VK_CHECK(vkAllocateCommandBuffers(_device, &cmdAllocInfo, &_frames[i]._mainCommandBuffer));
}
}
vkCreateX
ํจ์์ ์ฌ์ฉ๋๋ ๋๋ถ๋ถ์ Vulkan Info ๊ตฌ์กฐ์ฒด๋ค๊ณผ ๋ง์ ๋ค์ํ Vulkan ๊ตฌ์กฐ์ฒด๋ค์ sType
๊ณผ pNext
๋ฅผ ์๊ตฌํฉ๋๋ค. ์ด๋ ํ์ฅ์ ์ง์ํ๊ธฐ ์ํ ๊ฒ์ผ๋ก, ์ผ๋ถ ํ์ฅ์ ๋์ผํ vkCreateX
ํจ์๋ฅผ ํธ์ถํ์ง๋ง, ๋ค๋ฅธ ์ข
๋ฅ์ ๊ตฌ์กฐ์ฒด๋ฅผ ์๊ตฌํ๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค. sType
์ ํจ์์์ ์ฌ์ฉ๋๋ ๊ตฌ์กฐ์ฒด์ ์ข
๋ฅ๋ฅผ Vulkan
๊ตฌํ์ฒด๊ฐ ์ธ์ํ ์ ์๋๋ก ํฉ๋๋ค.
Vulkan ๊ตฌ์กฐ์ฒด๋ฅผ ์ฌ์ฉํ ๋ ์ด๋ฅผ ๋ฐ๋์ ์ํํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
VkCommandPoolCreateInfo commandPoolInfo = {};
` = {}`๋ฅผ ์์ฑํ๋ฉด ์ปดํ์ผ๋ฌ๊ฐ ๊ตฌ์กฐ์ฒด์ ๋ชจ๋ ๊ฐ์ 0์ผ๋ก ์ด๊ธฐํํฉ๋๋ค. ๋๋ถ๋ถ์ Vulkan ๊ตฌ์กฐ์ฒด๋ 0์ผ๋ก ์ค์ ๋์์ ๋ ๋น๊ต์ ์์ ํ๊ฒ ๋์ํ๊ธฐ ๋๋ฌธ์ ์ด๋ ๋งค์ฐ ์ค์ํฉ๋๋ค. ์ด๋ฅผ ํตํด ๊ตฌ์กฐ์ฒด ๋ด์ ์ด๊ธฐํ๋์ง ์์ ๊ฐ์ด ๋จ์ง ์๋๋ก ๋ณด์ฅํ ์ ์์ต๋๋ค.
queueFamilyIndex
์ ์ด์ ์ ๊ฐ์ ธ์จ _graphicsQueueFamily
๋ฅผ ์ค์ ํฉ๋๋ค. ์ด๋ ์ปค๋งจ๋ ํ์ด โ๊ทธ๋ํฝ์คโ ํจ๋ฐ๋ฆฌ์ ํ์ ์ฌ์ฉํ ์ ์๋ ์ปค๋งจ๋ ๋ฒํผ๋ฅผ ์์ฑํ๋๋ก ํฉ๋๋ค.
๋ํ .flags
์ธ์๋ ์ค์ ํด์ฃผ์ด์ผ ํฉ๋๋ค. ๋ง์ Vulkan ๊ตฌ์กฐ์ฒด๋ค์ ์ถ๊ฐ ์ต์
์ ์ค์ ํ๊ธฐ ์ํด .flags
์ธ์ง๋ฅผ ๊ฐ์ต๋๋ค. ์ฌ๊ธฐ์๋ VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
์ ์ ๋ฌํ๊ณ ์๋๋ฐ, ์ด๋ Vulkan์๊ฒ ํด๋น ํ์์ ์์ฑ๋ ๊ฐ๋ณ ์ปค๋งจ๋ ๋ฒํผ๋ฅผ ๋
๋ฆฝ์ ์ผ๋ก ๋ฆฌ์
ํ ์ ์๋๋ก ํ์ฉํ๋ ์ค์ ์
๋๋ค. ๋์์ผ๋ก๋ ์ ์ฒด ์ปค๋งจ๋ ํ์ ํ๋ฒ์ ๋ฆฌ์
ํ๋ ๋ฐฉ๋ฒ๋ ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ ํ์ ์ํ ๋ชจ๋ ์ปค๋งจ๋ ๋ฒํผ๊ฐ ํจ๊ป ์ด๊ธฐํ๋๋ฉฐ, ์ด๋ฌํ ๋ฐฉ์์์๋ ํด๋น ํ๋๊ทธ๋ฅผ ์ค์ ํ ํ์๊ฐ ์์ต๋๋ค.
๋ง์ง๋ง์ผ๋ก VkCreateCommandPool
๋ฅผ ํธ์ถํ ๋, VkDevice
, ์์ฑ ์ธ์๋ก ์ฌ์ฉํ commandPoolInfo
, ๊ทธ๋ฆฌ๊ณ _commandPool
๋ฉค๋ฒ์ ํฌ์ธํฐ๋ฅผ ์ ๋ฌํฉ๋๋ค. ์์ฑ์ด ์ฑ๊ณตํ๋ฉด _commandPool
๋ฉค๋ฒ๊ฐ ์๋ก์ด ํธ๋ค๋ก ๋ฎ์ด์์์ง๋๋ค.
๋ช
๋ น์ด ์ฑ๊ณตํ๋์ง ํ์ธํ๊ธฐ ์ํด VK_CHECK()
๋งคํฌ๋ก๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด๋ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด ์ฆ์ ํ๋ก๊ทธ๋จ์ ์ค๋จํ์ฌ ๋ฌธ์ ๋ฅผ ๊ฐ์งํ ์ ์๋๋ก ํฉ๋๋ค
์ด์ VkCommandPool
์ด ์์ฑ๋์ด _commandPool
๋ฉค๋ฒ์ ์ ์ฅ๋์์ผ๋ฏ๋ก, ์ด๋ฅผ ํตํด ์ปค๋งจ๋ ๋ฒํผ๋ฅผ ํ ๋นํ ์ ์์ต๋๋ค.
์ปค๋งจ๋ ํ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก, sType
๊ณผ pNext
๋ฅผ ์ค์ ํ๊ณ ๋๋จธ์ง Info ๊ตฌ์กฐ์ฒด์ ํ๋๋ฅผ ์ฑ์์ผ ํฉ๋๋ค.
Vulkan์๊ฒ ์ฐ๋ฆฌ๊ฐ ๋ฐฉ๊ธ ์์ฑํ _commandPool
์ ์ปค๋งจ๋ ๋ฒํผ์ ๋ถ๋ชจ๋ก ์ง์ ํ๋ฉฐ, ํ๋์ ์ปค๋งจ๋ ๋ฒํผ๋ง์ ์์ฑํ๊ฒ ๋ค๊ณ ์๋ ค์ค๋๋ค.
.commandBufferCount
์ธ์๋ฅผ ์ฌ์ฉํ๋ฉด ์ฌ๋ฌ ์ปค๋งจ๋ ๋ฒํผ๋ฅผ ํ ๋ฒ์ ํ ๋นํ ์ ์์ต๋๋ค. VkAllocateCommandBuffer
๋ก ์ ๋ฌํ๋ ํฌ์ธํฐ๊ฐ ํด๋น ๊ฐ์ ๋งํผ์ ๊ณต๊ฐ์ด ํ๋ณดํ๊ณ ์์ด์ผ ํฉ๋๋ค.
.level
์ Primary๋ก ์ค์ ํฉ๋๋ค. ์ปค๋งจ๋ ๋ฒํผ์ ๋ ๋ฒจ์ Primary ํน์ Secondary๊ฐ ๋ ์ ์์ต๋๋ค. Primary ๋ ๋ฒจ์ VkQueue๋ก ์ ๋ฌ๋์ด ๋ชจ๋ ์์
์ ์ํํฉ๋๋ค. ์ด ๊ฐ์ด๋์์๋ Primary๋ฅผ ์ฌ์ฉํ ๊ฒ์
๋๋ค. Secondary ๋ ๋ฒจ์ Primary ๋ฒํผ์ โํ์๋ช
๋ นโ ์ญํ ์ ํ ์ ์์ต๋๋ค. ๋ฉํฐ์ฐ๋ ๋ ๋จ์ผ ํจ์ค ํ๊ฒฝ์์ ๋ช
๋ น์ ๊ธฐ๋กํ ๋ ํํ ์ฌ์ฉ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ ์ฐ๋ฆฌ๊ฐ ๊ตฌ์ถํ ์ํคํ
์ฒ์์๋ ๋ฉํฐ์ฐ๋ ๋๋ก ์ฒ๋ฆฌํ ํ์๊ฐ ์์ผ๋ฏ๋ก Secondary ์ปค๋งจ๋ ๋ฒํผ๋ ์ฌ์ฉํ์ง ์์ ๊ฒ์
๋๋ค.
์ด๋ฌํ info ๊ตฌ์กฐ์ฒด์ ์ฌ์ฉ๋๋ ์ธ์์ ์ธ๋ถ์ฌํญ์ ๊ดํ ์ ๋ณด๋ ์๋ ๋งํฌ์์ ํ์ธํ ์ ์์ต๋๋ค.
VkInit ๋ชจ๋
ํ๋ก์ ํธ ํ์ผ์ ๋ค๋ฃฌ ๊ธ์ ๊ธฐ์ตํ๋ค๋ฉด, vk_initializers
๋ชจ๋์ด ๋ค์ํ Vulkan ๊ตฌ์กฐ์ฒด ์ด๊ธฐํ ๊ณผ์ ์ ์ถ์ํ๋ฅผ ํฌํจํ๋ค๊ณ ์ธ๊ธํ์์ต๋๋ค. ๋ค์ ๋ ๊ตฌ์กฐ์ฒด์ ๊ตฌํ์ ์ดํด๋ด
์๋ค.
VkCommandPoolCreateInfo vkinit::command_pool_create_info(uint32_t queueFamilyIndex,
VkCommandPoolCreateFlags flags /*= 0*/)
{
VkCommandPoolCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
info.pNext = nullptr;
info.queueFamilyIndex = queueFamilyIndex;
info.flags = flags;
return info;
}
VkCommandBufferAllocateInfo vkinit::command_buffer_allocate_info(
VkCommandPool pool, uint32_t count /*= 1*/)
{
VkCommandBufferAllocateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
info.pNext = nullptr;
info.commandPool = pool;
info.commandBufferCount = count;
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
return info;
}
์ปค๋งจ๋ ๋ฒํผ์ ๋ ๋ฒจ์ VK_COMMAND_BUFFER_LEVEL_PRIMARY
๋ก ํ๋์ฝ๋ฉํ ๊ฒ์
๋๋ค. ์ธ์ปจ๋๋ฆฌ ์ปค๋งจ๋ ๋ฒํผ๋ฅผ ์ฌ์ฉํ์ง ์์ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ์ด๋ฅผ ๋ฌด์ํ ์ ์์ต๋๋ค. ์์ง์ ๋ง๋ ๊ธฐ๋ณธ๊ฐ์ ์ค์ ํจ์ผ๋ก์ ์ ์ฒด์ ์ธ ๊ตฌ์กฐ๋ฅผ ๋จ์ํํ ์ ์์ต๋๋ค.
void VulkanEngine::init_commands()
{
//create a command pool for commands submitted to the graphics queue.
//we also want the pool to allow for resetting of individual command buffers
VkCommandPoolCreateInfo commandPoolInfo = vkinit::command_pool_create_info(_graphicsQueueFamily, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
for (int i = 0; i < FRAME_OVERLAP; i++) {
VK_CHECK(vkCreateCommandPool(_device, &commandPoolInfo, nullptr, &_frames[i]._commandPool));
// allocate the default command buffer that we will use for rendering
VkCommandBufferAllocateInfo cmdAllocInfo = vkinit::command_buffer_allocate_info(_frames[i]._commandPool, 1);
VK_CHECK(vkAllocateCommandBuffers(_device, &cmdAllocInfo, &_frames[i]._mainCommandBuffer));
}
}
๋ ๋ซ๊ณ ๋ ์งง์์ก์ต๋๋ค. ๊ฐ์ด๋๋ฅผ ๊ฑฐ์น๋ฉฐ vkinit
๋ค์์คํ์ด์ค๋ฅผ ์ฌ์ฉํ๊ฒ ์ต๋๋ค. ์ด ๋ค์์คํ์ด์ค๋ ๋งค์ฐ ๊ฐ๋จํ๋ฏ๋ก, ๋ค๋ฅธ ํ๋ก์ ํธ์์๋ ์์ ํ๊ฒ ์ฌ์ฌ์ฉํ ์ ์์ต๋๋ค. 0์ฅ์์ ์ค๋ช
ํ๋๋ก starting_point ๋ธ๋์น์ ์์ฑ๋์์์ ์ ์ํ์ธ์.
์ ๋ฆฌ
์ด์ ๊ณผ ๊ฐ์ด ์์ฑํ ๊ฐ์ฒด๋ฅผ ํ๊ดดํด์ผ ํฉ๋๋ค.
void VulkanEngine::cleanup()
{
if (_isInitialized) {
//make sure the gpu has stopped doing its things
vkDeviceWaitIdle(_device);
for (int i = 0; i < FRAME_OVERLAP; i++) {
vkDestroyCommandPool(_device, _frames[i]._commandPool, nullptr);
}
// --- rest of code
}
}
์ปค๋งจ๋ ํ์ด ๊ฐ์ฅ ์ต๊ทผ์ ์์ฑํ Vulkan ๊ฐ์ฒด์ด๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ๊ฐ์ฒด๋ณด๋ค ๋จผ์ ํ๊ดดํด์ผ ํฉ๋๋ค. VkCommandBuffer
๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ํ๊ดดํ ์๋ ์์ต๋๋ค. ๋์ ์ปค๋งจ๋ ํ์ด ํ๊ดด๋๋ฉด ํด๋น ํ์์ ํ ๋น๋ ๋ชจ๋ ์ปค๋งจ๋ ๋ฒํผ๊ฐ ํจ๊ป ํ๊ดด๋ฉ๋๋ค.
๋ํ VkQueue
๋ค์ VkPhysicalDevice
์ฒ๋ผ ํ๊ดด๋ ์ ์์ต๋๋ค. ์ด๋ค์ ์ค์ ๋ก ์์ฑ๋ ๊ฐ์ฒด๊ฐ ์๋๋ผ VkInstance
์ ์ผ๋ถ์ ๋ํ ํธ๋ค์ด๊ธฐ ๋๋ฌธ์
๋๋ค.
์ด์ GPU๋ก ๋ช ๋ น์ ์ ์กํ ๋ฐฉ๋ฒ์ ๋ง๋ จํ์ง๋ง, CPU์ GPU๊ฐ ์คํ์ ๋๊ธฐํํ ๊ตฌ์กฐ์ฒด๋ฅผ ๊ตฌํํด์ผ ํฉ๋๋ค.
Next: Rendering Loop