์ด์ ํ ์ค์ณ๋ฅผ ์ง์ํ๊ณ ๋ณต์ก๋๊ฐ ํฌ๊ฒ ์ฆ๊ฐํจ์ ๋ฐ๋ผ ์์ง ์ถ์ํ๋ฅผ ํ์ฅํด์ผ ํฉ๋๋ค. ํนํ ๋์คํฌ๋ฆฝํฐ ์ ์ ๋ํด ๋ ๋์ ์ถ์ํ๊ฐ ํ์ํฉ๋๋ค.
2์ฅ์์๋ ์ด๋ฏธ DescriptorAllocator์ DescriptorLayoutBuilder๋ผ๋ 2๊ฐ์ ํด๋์ค๋ฅผ ์์ฑํ์ต๋๋ค. DescriptorAllocator๋ ํ๋์ VkDescriptorPool๋ฅผ ์ฌ์ฉํด ๋์คํฌ๋ฆฝํฐ๋ฅผ ํ ๋นํ๋ ๊ธฐ๋ณธ์ ์ธ ์ถ์ํ๋ฅผ ์ ๊ณตํ๊ณ , LayoutBuilder๋ ๋์คํฌ๋ฆฝํฐ ์ ๋ ์ด์์ ์์ฑ์ ์ถ์ํํฉ๋๋ค.
Descriptor Allocator 2
์ด์ ์ฐ๋ฆฌ๋ DescriptorAllocatorGrowable
์ด๋ผ๋ ์๋ก์ด ๋ฒ์ ์ ๋์คํฌ๋ฆฝํฐ ํ ๋น๊ธฐ๋ฅผ ๋ง๋ค๊ฒ ์ต๋๋ค. ์ด์ ์ ์์ฑํ๋ ๊ฒ์ ๋์คํฌ๋ฆฝํฐ ํ์ ๊ณต๊ฐ์ด ๋ถ์กฑํ๋ฉด ๊ทธ๋๋ก ํฌ๋์๊ฐ ๋ฐ์ํฉ๋๋ค. ์ด๋ ํ์ํ ๋์คํฌ๋ฆฝํฐ ์
์ ์๋ฅผ ์ฌ์ ์ ์ ์ ์๋ ์ํฉ์์๋ ๊ด์ฐฎ์ง๋ง, ์์์ ํ์ผ๋ก๋ถํฐ ๋ฉ์๋ฅผ ๋ถ๋ฌ์ค๋ ์ํฉ์์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ผ๋ง๋ ๋ง์ ๋์คํฌ๋ฆฝํฐ๊ฐ ํ์ํ์ง ์์ธกํ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค. ์๋ก์ด ํด๋์ค๋ ๊ธฐ์กด ๋ฐฉ์๊ณผ ๊ฑฐ์ ๋์ผํ๊ฒ ๋์ํ์ง๋ง, ๋จ์ผ ํ์ ๋ค๋ฃจ๋ ๊ฒ ๋์ ์ฌ๋ฌ ๊ฐ์ ํ์ ๊ด๋ฆฌํฉ๋๋ค. ํ ๋น์ ์คํจํ ๊ฒฝ์ฐ, ์๋ก์ด ๋์คํฌ๋ฆฝํฐ ํ์ ์์ฑํฉ๋๋ค. ์ด ํ ๋น๊ธฐ๋ฅผ ํด์ ํ๋ฉด ๊ด๋ฆฌ์ค์ธ ๋ชจ๋ ํ์ ์ ๋ฆฌํฉ๋๋ค. ์ด ๋ฐฉ๋ฒ์ผ๋ก 1๊ฐ์ DescriptorAllocator๋ฅผ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ํ์์ ๋ฐ๋ผ ์๋์ผ๋ก ํ์ฅ๋ฉ๋๋ค.
์๋๋ vk_descriptors.h์ ๋ค์ด๊ฐ ๊ตฌํ๋ถ์ ๋๋ค.
struct DescriptorAllocatorGrowable {
public:
struct PoolSizeRatio {
VkDescriptorType type;
float ratio;
};
void init(VkDevice device, uint32_t initialSets, std::span<PoolSizeRatio> poolRatios);
void clear_pools(VkDevice device);
void destroy_pools(VkDevice device);
VkDescriptorSet allocate(VkDevice device, VkDescriptorSetLayout layout, void* pNext = nullptr);
private:
VkDescriptorPool get_pool(VkDevice device);
VkDescriptorPool create_pool(VkDevice device, uint32_t setCount, std::span<PoolSizeRatio> poolRatios);
std::vector<PoolSizeRatio> ratios;
std::vector<VkDescriptorPool> fullPools;
std::vector<VkDescriptorPool> readyPools;
uint32_t setsPerPool;
};
public ์ธํฐํ์ด์ค๋ ์ด์ ์ DescriptorAllocator์ ๋์ผํฉ๋๋ค. ๋ฌ๋ผ์ง ์ ์ PoolSizeRatio์ ๋ฐฐ์ด(ํ์ ์ฌํ ๋น ํ ๋ ํ์ํฉ๋๋ค), ํ๋ง๋ค ํ ๋นํ ๋์คํฌ๋ฆฝํฐ ์
์ ์, ๊ทธ๋ฆฌ๊ณ 2๊ฐ์ ๋ฐฐ์ด์
๋๋ค. fullPools
๋ ๋์ด์ ํ ๋นํ ์ ์๋ ํ์ด ๋ค์ด๊ฐ๊ณ , ๊ทธ๋ฆฌ๊ณ readyPools
๋ ์์ง ์ฌ์ฉํ ์ ์๋ ํ์ด๋ ์๋ก ์์ฑ๋ ํ์ด ๋ค์ด๊ฐ๋๋ค.
ํ ๋น ๋ก์ง์ ๋จผ์ readyPools์์ ํ์ ํ๋ ๊ฐ์ ธ์ ํ ๋น์ ์๋ํฉ๋๋ค. ํ ๋น์ด ์ฑ๊ณตํ๋ฉด ํ์ ๋ค์ readyPools ๋ฐฐ์ด๋ก ๋ฃ์ต๋๋ค. ๋ง์ฝ ์คํจํ๋ค๋ฉด fullPools ๋ฐฐ์ด๋ก ์ฎ๊ธด ๋ค ๋ค๋ฅธ ํ์ ๊ฐ์ ธ์ ๋ค์ ์๋ํฉ๋๋ค. get_pool
ํจ์๋ readyPools๋ก๋ถํฐ ํ์ ์ ํํ๊ฑฐ๋ ์๋ก์ด ํ์ ์์ฑํฉ๋๋ค.
get_pool๊ณผ create_pool ํจ์๋ฅผ ์์ฑํด๋ด ์๋ค.
VkDescriptorPool DescriptorAllocatorGrowable::get_pool(VkDevice device)
{
VkDescriptorPool newPool;
if (readyPools.size() != 0) {
newPool = readyPools.back();
readyPools.pop_back();
}
else {
//need to create a new pool
newPool = create_pool(device, setsPerPool, ratios);
setsPerPool = setsPerPool * 1.5;
if (setsPerPool > 4092) {
setsPerPool = 4092;
}
}
return newPool;
}
VkDescriptorPool DescriptorAllocatorGrowable::create_pool(VkDevice device, uint32_t setCount, std::span<PoolSizeRatio> poolRatios)
{
std::vector<VkDescriptorPoolSize> poolSizes;
for (PoolSizeRatio ratio : poolRatios) {
poolSizes.push_back(VkDescriptorPoolSize{
.type = ratio.type,
.descriptorCount = uint32_t(ratio.ratio * setCount)
});
}
VkDescriptorPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_info.flags = 0;
pool_info.maxSets = setCount;
pool_info.poolSizeCount = (uint32_t)poolSizes.size();
pool_info.pPoolSizes = poolSizes.data();
VkDescriptorPool newPool;
vkCreateDescriptorPool(device, &pool_info, nullptr, &newPool);
return newPool;
}
get_pools์์๋ ์๋ก์ด ํ์ ์์ฑํ ๋ setsPerPool์ ์ฆ๊ฐ์์ผ ๋ง์น std::vector์ resize์ฒ๋ผ ์๋ํฉ๋๋ค. ํ์ง๋ง ๋๋ฌด ์ปค์ง๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ ์ํด ํ๋ง๋ค ๋์คํฌ๋ฆฝํฐ ์ ์ ์ต๋ ๊ฐ์๋ 4092๋ก ์ ํํฉ๋๋ค. ์ด ์ ํ์ ์ฌ์ฉ์์ ์ํฉ์ ๋ฐ๋ผ ๋ฐ๋ ์ ์์ต๋๋ค.
ํจ์์์ ์ค์ํ ์ ์ ํ์ ๊ฐ์ ธ์ฌ ๋ readyPools์์ ํด๋น ํ์ ์ ๊ฑฐํ๋ค๋ ์ ์ ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋์คํฌ๋ฆฝํฐ ํ ๋น ํ ํด๋น ํ์ ๋ค์ readyPools ๋๋ ๋ค๋ฅธ ๋ฐฐ์ด์ ๋ฃ์ ์ ์์ต๋๋ค.
create_pool ํจ์๋ ์ด์ ์ ๋ค๋ฅธ descriptorAllocator์์ ํ๋ ๊ฒ๊ณผ ๋์ผํฉ๋๋ค.
์ด์ ํ์ํ ๋ค๋ฅธ ํจ์๋ ์์ฑํด๋ด ์๋ค.
void DescriptorAllocatorGrowable::init(VkDevice device, uint32_t maxSets, std::span<PoolSizeRatio> poolRatios)
{
ratios.clear();
for (auto r : poolRatios) {
ratios.push_back(r);
}
VkDescriptorPool newPool = create_pool(device, maxSets, poolRatios);
setsPerPool = maxSets * 1.5; //grow it next allocation
readyPools.push_back(newPool);
}
void DescriptorAllocatorGrowable::clear_pools(VkDevice device)
{
for (auto p : readyPools) {
vkResetDescriptorPool(device, p, 0);
}
for (auto p : fullPools) {
vkResetDescriptorPool(device, p, 0);
readyPools.push_back(p);
}
fullPools.clear();
}
void DescriptorAllocatorGrowable::destroy_pools(VkDevice device)
{
for (auto p : readyPools) {
vkDestroyDescriptorPool(device, p, nullptr);
}
readyPools.clear();
for (auto p : fullPools) {
vkDestroyDescriptorPool(device,p,nullptr);
}
fullPools.clear();
}
init ํจ์๋ ์ฒซ ๋์คํฌ๋ฆฝํฐ ํ์ ํ ๋นํ๊ณ readyPools ๋ฐฐ์ด๋ก ์ถ๊ฐํ๊ธฐ๋ง ํฉ๋๋ค.
ํ์ ์ด๊ธฐํํ๋ ๊ฒ์ ๋ชจ๋ ํ์ ์ด๊ธฐํํ๊ณ fullPools ๋ฐฐ์ด์ ๋ชจ๋ ํ์ readyPools ๋ฐฐ์ด๋ก ๋ณต์ฌํ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
ํ๊ดด ๊ณผ์ ์์๋ ๋ ๋ฐฐ์ด์ ๋ชจ๋ ์ํํ๋ฉฐ ๋ชจ๋ ํ์ ์ ๊ฑฐํ์ฌ ํ ๋น๊ธฐ๋ฅผ ์์ ํ ์ ๋ฆฌํฉ๋๋ค.
๋ง์ง๋ง์ ์๋ก์ด ํ ๋น ํจ์์ ๋๋ค.
VkDescriptorSet DescriptorAllocatorGrowable::allocate(VkDevice device, VkDescriptorSetLayout layout, void* pNext)
{
//get or create a pool to allocate from
VkDescriptorPool poolToUse = get_pool(device);
VkDescriptorSetAllocateInfo allocInfo = {};
allocInfo.pNext = pNext;
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = poolToUse;
allocInfo.descriptorSetCount = 1;
allocInfo.pSetLayouts = &layout;
VkDescriptorSet ds;
VkResult result = vkAllocateDescriptorSets(device, &allocInfo, &ds);
//allocation failed. Try again
if (result == VK_ERROR_OUT_OF_POOL_MEMORY || result == VK_ERROR_FRAGMENTED_POOL) {
fullPools.push_back(poolToUse);
poolToUse = get_pool(device);
allocInfo.descriptorPool = poolToUse;
VK_CHECK( vkAllocateDescriptorSets(device, &allocInfo, &ds));
}
readyPools.push_back(poolToUse);
return ds;
}
๋จผ์ ํ์ ๊ฐ์ ธ์ ํ ๋นํฉ๋๋ค. ๋ง์ฝ ํ ๋น์ด ์คํจํ๋ค๋ฉด ํด๋น ํ์ ๊ฐ๋ ์ฐผ๋ค๊ณ ํ๋จํ์ฌ fullPools ๋ฐฐ์ด์ ์ถ๊ฐํ๊ณ ๋ค๋ฅธ ํ์ ํตํด ๋ค์ ํ ๋น์ ์๋ํฉ๋๋ค. ๋ง์ฝ ๋ ๋ฒ์งธ์๋ ํ ๋น์ด ์คํจํ๋ค๋ฉด ์ฌ๊ฐํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ๊ฒ์ผ๋ก ๊ฐ์ฃผํ๊ณ assert๋ก ํฌ๋์๋ฅผ ์ผ์ผํต๋๋ค. ํ๋ก๋ถํฐ ํ ๋น์ด ์ฑ๊ณตํ๋ฉด readyPools ๋ฐฐ์ด์ ์ถ๊ฐํฉ๋๋ค.
Descriptor Writer
์ปดํจํธ ์
ฐ์ด๋์ ์ฌ์ฉํ ๋์คํฌ๋ฆฝํฐ ์
์ ๋ง๋ค ๋ vkUpdateDescriptorSets
๋ฅผ ์๋์ผ๋ก ํธ์ถํด ์ฌ์ฉํ์ต๋๋ค. ํ์ง๋ง ์ด ๋ฐฉ์์ ๋งค์ฐ ๋ฒ๊ฑฐ๋กญ๊ณ ๊ด๋ฆฌํ๊ธฐ ์ด๋ ต์ต๋๋ค. ๋ฐ๋ผ์ ์ด ๋ถ๋ถ๋ ์ถ์ํ๋ฅผ ์งํํ๊ฒ ์ต๋๋ค. ์ฐ๋ฆฌ์ writer์์๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ธ๋ฉํ๊ธฐ ์ํด write_image
์ write_buffer
ํจ์๋ฅผ ์ฌ์ฉํ ๊ฒ์
๋๋ค. vk_descriptors.h ํ์ผ์ ์ ์ธ๋ ๊ตฌ์กฐ์ฒด๋ฅผ ์ดํด๋ด
์๋ค.
struct DescriptorWriter {
std::deque<VkDescriptorImageInfo> imageInfos;
std::deque<VkDescriptorBufferInfo> bufferInfos;
std::vector<VkWriteDescriptorSet> writes;
void write_image(int binding,VkImageView image,VkSampler sampler , VkImageLayout layout, VkDescriptorType type);
void write_buffer(int binding,VkBuffer buffer,size_t size, size_t offset,VkDescriptorType type);
void clear();
void update_set(VkDevice device, VkDescriptorSet set);
};
์ฌ๊ธฐ์๋ std::deque๋ฅผ ์ฌ์ฉํ์ฌ ๋ช ๊ฐ์ง ๋ฉ๋ชจ๋ฆฌ ํธ๋ฆญ์ ์ฌ์ฉํ ๊ฒ์
๋๋ค. std::deque์ ์์์ ๋ํ ํฌ์ธํฐ๊ฐ ์ ํจํ๊ฒ ์ ์ง๋๋ค๋ ๊ฒ์ด ๋ณด์ฅ๋๋ฏ๋ก, ์๋ก์ด VkWriteDescriptorSet
์ writes ๋ฐฐ์ด๋ก ์ถ๊ฐํ ๋ ์ด ์ ์ ํ์ฉํ ์ ์์ต๋๋ค.
VkWriteDescriptorSet
์ ์ ์๋ฅผ ์ดํด๋ด
์๋ค.
typedef struct VkWriteDescriptorSet {
VkStructureType sType;
const void* pNext;
VkDescriptorSet dstSet;
uint32_t dstBinding;
uint32_t dstArrayElement;
uint32_t descriptorCount;
VkDescriptorType descriptorType;
const VkDescriptorImageInfo* pImageInfo;
const VkDescriptorBufferInfo* pBufferInfo;
const VkBufferView* pTexelBufferView;
} VkWriteDescriptorSet;
ํ๊ฒ ๋์คํฌ๋ฆฝํฐ ์ ๊ณผ ๋ฐ์ธ๋ฉ ์์๊ฐ ์์ผ๋ฉฐ, ์ค์ ๋ฒํผ๋ ์ด๋ฏธ์ง๋ ํฌ์ธํฐ๋ก ์ ๋ฌ๋ฉ๋๋ค. ๋ฐ๋ผ์ VkDescriptorBufferInfo ๋ฑ์ ์ ๋ณด๋ฅผ ํฌ์ธํฐ๊ฐ ์์ ์ ์ผ๋ก ์ ์ง๋๋๋ก ๋ณด์กดํ๊ฑฐ๋, ์ต์ข WriteDescriptorSet ๋ฐฐ์ด์ ๋ง๋ค ๋ ํฌ์ธํฐ๋ฅผ ์์ ํ ์ ์๋ ๋ฐฉ์์ผ๋ก ๊ด๋ฆฌํด์ผ ํฉ๋๋ค.
write_buffer๊ฐ ์ด๋ค ์ผ์ ํ๋ ์ง ์ดํด๋ด ์๋ค.
void DescriptorWriter::write_buffer(int binding, VkBuffer buffer, size_t size, size_t offset, VkDescriptorType type)
{
VkDescriptorBufferInfo& info = bufferInfos.emplace_back(VkDescriptorBufferInfo{
.buffer = buffer,
.offset = offset,
.range = size
});
VkWriteDescriptorSet write = {.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET};
write.dstBinding = binding;
write.dstSet = VK_NULL_HANDLE; //left empty for now until we need to write it
write.descriptorCount = 1;
write.descriptorType = type;
write.pBufferInfo = &info;
writes.push_back(write);
}
๋จผ์ VkDescriptorBufferInfo๋ฅผ ์ฑ์์ผ ํฉ๋๋ค. ์ด๋ ๋ฒํผ ์์ฒด์ ์คํ์ , ๊ทธ๋ฆฌ๊ณ ๋ฒ์(size)๋ฅผ ์ค์ ํฉ๋๋ค.
๊ทธํ, write ๊ฐ์ฒด ์์ฒด๋ฅผ ์ค์ ํด์ผ ํฉ๋๋ค. ํ๋์ ๋์คํฌ๋ฆฝํฐ์ ๋ํด ์ง์ ๋ ๋ฐ์ธ๋ฉ ์ฌ๋กฏ์ ์ฌ๋ฐ๋ฅธ ํ์ ๊ณผ ํจ๊ป VkDescriptorBufferInfo์ ๋ํ ํฌ์ธํฐ๋ฅผ ์ง์ ํฉ๋๋ค. ํด๋น info๋ std::deque์ emplace_back์ผ๋ก ์์ฑํ๊ธฐ ๋๋ฌธ์, ํฌ์ธํฐ๋ฅผ ์์ ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ฒํผ์ ์ฌ์ฉํ ์ ์๋ ๋์คํฌ๋ฆฝํฐ ํ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC
์ด๋ฌํ ๋ฒํผ ํ์ ๋ค์ ์ง๋ ์ฑํฐ์์ ์ด๋ฏธ ์ค๋ช ํ์ต๋๋ค. ์ ฐ์ด๋์ ํน์ ํ์ ์ ๋ฒํผ๋ฅผ ๋ฐ์ธ๋ฉํ๋ ค๋ฉด, ์ฌ๊ธฐ์ ์ฌ๋ฐ๋ฅธ ๋์คํฌ๋ฆฝํฐ ํ์ ์ ์ง์ ํด์ผ ํฉ๋๋ค. VkBuffer๋ฅผ ํ ๋นํ ๋ ์ง์ ํ Usage ํ๋๊ทธ์ ์ผ์น์์ผ์ผํ๋ค๋ ์ ์ ๊ธฐ์ตํ์ธ์.
์ด๋ฏธ์ง์๋ ๋ค๋ฅธ ํจ์๋ฅผ ์ฌ์ฉํฉ๋๋ค.
void DescriptorWriter::write_image(int binding,VkImageView image, VkSampler sampler, VkImageLayout layout, VkDescriptorType type)
{
VkDescriptorImageInfo& info = imageInfos.emplace_back(VkDescriptorImageInfo{
.sampler = sampler,
.imageView = image,
.imageLayout = layout
});
VkWriteDescriptorSet write = { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
write.dstBinding = binding;
write.dstSet = VK_NULL_HANDLE; //left empty for now until we need to write it
write.descriptorCount = 1;
write.descriptorType = type;
write.pImageInfo = &info;
writes.push_back(write);
}
๋ฒํผ์ ์ ์ฌํ์ง๋ง Info ํ์
์ด ๋ค๋ฆ
๋๋ค. VkDescriptorImageInfo
๋ฅผ ๋์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค. ์ฌ๊ธฐ์๋ ์ํ๋ฌ์ ์ด๋ฏธ์ง ๋ทฐ, ์ด๋ฏธ์ง๊ฐ ์ฌ์ฉํ๋ ๋ ์ด์์์ ์ ๋ฌํด์ผ ํฉ๋๋ค. ๋ ์ด์์์ ๋๋ถ๋ถ ์
ฐ์ด๋์์ ํ
์ค์ณ์ ์ ๊ทผํ ๋ ์ต์ ์ ๋ ์ด์์์ธ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
์ด๊ฑฐ๋ ์ปดํจํธ ์
ฐ์ด๋์์ ์ฐ๊ธฐ๋ฅผ ์ํํ ๋ ์ฌ์ฉํ๋ VK_IMAGE_LAYOUT_GENERAL
์ ์ฌ์ฉํฉ๋๋ค.
์ด ImageInfo์ ์ธ ๊ฐ์ง ํ๋ผ๋ฏธํฐ๋ ์ ํ์ด์ง๋ง, ์ํฉ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋๋ค.
VK_DESCRIPTOR_TYPE_SAMPLER
๋ ์ํ๋ฌ ๋ฟ์ ๋๋ค. ๋ฐ๋ผ์ ImageView๋ ๋ ์ด์์์ ์ค์ ํ ํ์๊ฐ ์์ต๋๋ค.VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
๋ ์ ฐ์ด๋์์ ๋ค๋ฅธ ์ํ๋ฌ์ ์ ๊ทผ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ์ํ๋ฌ๋ฅผ ์๊ตฌํ์ง ์์ต๋๋ค. ๋ฐ๋ผ์ ์ด ๋์คํฌ๋ฆฝํฐ ํ์ ์ ์ด๋ฏธ์ง์ ํฌ์ธํฐ์ผ ๋ฟ์ ๋๋ค.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
๋ ๋ชจ๋ ๊ฒ์ ์ค์ ํด์ผ ํฉ๋๋ค. ์ํ๋ฌ์ ์ํ๋งํ ์ด๋ฏธ์ง์ ๋ํ ์ ๋ณด ๋ชจ๋๋ฅผ ๋ด์์ผ ํฉ๋๋ค. ์ด๋ ํ ์ค์ณ์ ์ ๊ทผํ๊ธฐ ์ํด 1๊ฐ์ ๋์คํฌ๋ฆฝํฐ๋ง ๋ฐ์ธ๋ฉํ๋ฉด ๋๊ธฐ ๋๋ฌธ์ ์ ์ฉํ ํ์ ์ ๋๋ค.VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
๋ 2์ฅ์์ ์ฌ์ฉํ์ต๋๋ค. ์ด๋ ์ํ๋ฌ๋ฅผ ์๊ตฌํ์ง ์์ผ๋ฉฐ ํฝ์ ๋ฐ์ดํฐ์ ์ง์ ์ ๊ทผํ๋ ์ปดํจํธ์ ฐ์ด๋์์ ์ฌ์ฉ๋ฉ๋๋ค.
write_image์ write_buffer ํจ์๋ ๋ค์ ์ผ๋ฐ์ ์ผ๋ก ๊ตฌํ๋์ด ์์ต๋๋ค. ์ด๋ ๋จ์ํจ์ ์ํ ๊ฒ์ด์ง๋ง, ํ์ํ๋ค๋ฉด VK_DESCRIPTOR_TYPE_SAMPLER
๋ฅผ ์ฌ์ฉํ๊ณ imageView์ layout์ null๋ก ์ค์ ํ๋ write_sampler()
์ ๊ฐ์ ํจ์๋ฅผ ์ถ๊ฐํ์ฌ ๋ ๊ตฌ์ฒด์ ์ธ ์ถ์ํ๋ฅผ ๋ง๋ค ์๋ ์์ต๋๋ค
์ด์ ์ด๋ฅผ ๋ฐํ์ผ๋ก ์ค์ write ์์ ์ ์ํํ ์ ์์ต๋๋ค.
void DescriptorWriter::clear()
{
imageInfos.clear();
writes.clear();
bufferInfos.clear();
}
void DescriptorWriter::update_set(VkDevice device, VkDescriptorSet set)
{
for (VkWriteDescriptorSet& write : writes) {
write.dstSet = set;
}
vkUpdateDescriptorSets(device, (uint32_t)writes.size(), writes.data(), 0, nullptr);
}
clear()ํจ์๋ ๋ชจ๋ ์ํ๋ฅผ ์ด๊ธฐํํฉ๋๋ค. update_set ํจ์๋ ๋๋ฐ์ด์ค์ ๋์คํฌ๋ฆฝํฐ ์
์ ์
๋ ฅ๋ฐ์ ํด๋น ์
์ writes์ ๋ฐฐ์ด์ ์ฐ๊ฒฐํ ๋ค, vkUpdateDescriptorSets
๋ฅผ ํธ์ถํด ๋์คํฌ๋ฆฝํฐ ์
์ ์๋ก์ด ๋ฐ์ธ๋ฉ์ ์ ์ฉํฉ๋๋ค.
์ด ์ถ์ํ๋ฅผ ํตํด ๊ธฐ์กด init_descriptors
ํจ์์์ ์ฌ์ฉํ๋ ์ฝ๋๋ฅผ ์ด๋ป๊ฒ ๋์ฒดํ ์ ์๋์ง ์ดํด๋ด
์๋ค.
before:
VkDescriptorImageInfo imgInfo{};
imgInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
imgInfo.imageView = _drawImage.imageView;
VkWriteDescriptorSet drawImageWrite = {};
drawImageWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
drawImageWrite.pNext = nullptr;
drawImageWrite.dstBinding = 0;
drawImageWrite.dstSet = _drawImageDescriptors;
drawImageWrite.descriptorCount = 1;
drawImageWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
drawImageWrite.pImageInfo = &imgInfo;
vkUpdateDescriptorSets(_device, 1, &drawImageWrite, 0, nullptr);
after:
DescriptorWriter writer;
writer.write_image(0, _drawImage.imageView, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_GENERAL, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
writer.update_set(_device,_drawImageDescriptors);
์ด ์ถ์ํ๋ allocator์ layout builder๋ฅผ ๊ฒฐํฉํ์ฌ ์ข ๋ ๋ณต์กํ ๋์คํฌ๋ฆฝํฐ ์ ์ ๊ด๋ฆฌํ ๋ ๋ ์ ์ฉํ ๊ฒ์ ๋๋ค.
๋์ ๋์คํฌ๋ฆฝํฐ ํ ๋น
์ด์ ์ด ์ถ์ํ๋ฅผ ์ฌ์ฉํ์ฌ ๋งค ํ๋ ์๋ง๋ค ์ ์ญ ์ฌ ๋ฐ์ดํฐ ๋์คํฌ๋ฆฝํฐ๋ฅผ ์์ฑํด ๋ด ์๋ค. ์ด ๋์คํฌ๋ฆฝํฐ ์ ์ ๋ชจ๋ ๋๋ก์ฐ์ฝ๋ง๋ค ์ฌ์ฉ๋๋ฉฐ, ์นด๋ฉ๋ผ ํ๋ ฌ์ ํฌํจํ์ฌ 3D ๋ ๋๋ง์ด ๊ฐ๋ฅํ๋๋ก ํด์ค ๊ฒ์ ๋๋ค.
๋์คํฌ๋ฆฝํฐ ์ ์ ๋ฐํ์์ ํ ๋นํ๊ธฐ ์ํด์ FrameData ๊ตฌ์กฐ์ฒด์ DescriptorAllocator๋ฅผ ๋ด์ต๋๋ค. ์ด ๋ฐฉ์์ ์ญ์ ํ์ฒ๋ผ ์๋ํ์ฌ, ํ๋ ์ ๋ ๋๋ง์ ์์ํ ๋ ์์์ ์ ๋ฆฌํ์ฌ ํ๊ดดํฉ๋๋ค. ๊ฐ๋ณ ๋์คํฌ๋ฆฝํฐ ์ ์ ์๋ช ์ ์ถ์ ํ๋ ๊ฒ๋ณด๋ค ์ ์ฒด ๋์คํฌ๋ฆฝํฐ ํ์ ํ ๋ฒ์ ๋ฆฌ์ ํ๋ ๋ฐฉ์์ด ํจ์ฌ ๋น ๋ฆ ๋๋ค.
์ด๋ฅผ FrameData ๊ตฌ์กฐ์ฒด์ ์ถ๊ฐํฉ๋๋ค.
struct FrameData {
VkSemaphore _swapchainSemaphore, _renderSemaphore;
VkFence _renderFence;
VkCommandPool _commandPool;
VkCommandBuffer _mainCommandBuffer;
DeletionQueue _deletionQueue;
DescriptorAllocatorGrowable _frameDescriptors;
};
์ด์ ์ค์์ฒด์ธ๊ณผ ํด๋น ๊ตฌ์กฐ์ฒด๋ฅผ ์ด๊ธฐํํ ๋ ํจ๊ป ์ด๊ธฐํํฉ์๋ค. init_descriptors() ํจ์์ ๋์ ๋ค์ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
for (int i = 0; i < FRAME_OVERLAP; i++) {
// create a descriptor pool
std::vector<DescriptorAllocatorGrowable::PoolSizeRatio> frame_sizes = {
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 3 },
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3 },
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3 },
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 4 },
};
_frames[i]._frameDescriptors = DescriptorAllocatorGrowable{};
_frames[i]._frameDescriptors.init(_device, 1000, frame_sizes);
_mainDeletionQueue.push_function([&, i]() {
_frames[i]._frameDescriptors.destroy_pools(_device);
});
}
๊ทธํ, ๋งค ํ๋ ์๋ง๋ค ์ญ์ ํ๋ฅผ flush ํ ๋ ์ด๋ฅผ ์ ๋ฆฌํ ์ ์์ต๋๋ค. ์ด ์ฝ๋๋ draw() ํจ์์ ์์ ๋ถ๋ถ์ ์์นํฉ๋๋ค.
//wait until the gpu has finished rendering the last frame. Timeout of 1 second
VK_CHECK(vkWaitForFences(_device, 1, &get_current_frame()._renderFence, true, 1000000000));
get_current_frame()._deletionQueue.flush();
get_current_frame()._frameDescriptors.clear_pools(_device);
์ด์ ๋์คํฌ๋ฆฝํฐ ์ ์ ๋์ ์ผ๋ก ํ ๋นํ ์ ์์ต๋๋ค. ์ฌ ๋ฐ์ดํฐ๋ฅผ ๋ด์ ๋ฒํผ๋ฅผ ํ ๋นํ๊ณ ํด๋น ๋์คํฌ๋ฆฝํฐ ์ ์ ์์ฑํ๊ฒ ์ต๋๋ค.
์ฌ ๋ฐ์ดํฐ์ ์ ๋ํผ ๋ฒํผ์ ์ฌ์ฉํ๋ ์๋ก์ด ๊ตฌ์กฐ์ฒด๋ฅผ ์ถ๊ฐํฉ์๋ค. ๋ทฐ ํ๋ ฌ๊ณผ ํฌ์ ํ๋ ฌ์ ๊ฐ๋ณ์ ์ผ๋ก ์ ์ฅํ๊ณ , ๋ฏธ๋ฆฌ ๊ณฑํ view-projection ํ๋ ฌ๋ ํฌํจํฉ๋๋ค. ๋ํ ์ดํ์ ๊ตฌ์ฑํ ์์ฃผ ๊ธฐ๋ณธ์ ์ธ ์กฐ๋ช ๋ชจ๋ธ์ ํ์ํ ๋ช ๊ฐ์ง vec4๋ ์ถ๊ฐํฉ๋๋ค.
struct GPUSceneData {
glm::mat4 view;
glm::mat4 proj;
glm::mat4 viewproj;
glm::vec4 ambientColor;
glm::vec4 sunlightDirection; // w for sun power
glm::vec4 sunlightColor;
};
VulkanEngine ํด๋์ค์ ์๋ก์ด ๋์คํฌ๋ฆฝํฐ ๋ ์ด์์์ ์ถ๊ฐํฉ๋๋ค.
GPUSceneData sceneData;
VkDescriptorSetLayout _gpuSceneDataDescriptorLayout;
init_descriptorsํจ์์์ ๋์คํฌ๋ฆฝํฐ ์ ๋ ์ด์์์ ์์ฑํฉ๋๋ค. ์ด ๋์คํฌ๋ฆฝํฐ ์ ์ ํ๋์ ์ ๋ํผ ๋ฒํผ๋ง์ ๋ฐ์ธ๋ฉํฉ๋๋ค. ๋ฒํผ๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ฌ๊ธฐ์๋ SSBO ๋์ ์ ๋ํผ ๋ฒํผ๋ฅผ ์ฌ์ฉํ๋ฉฐ, ๋ฒํผ ๋๋ฐ์ด์ค ์ด๋๋ ์ค๋ฅผ ์ฌ์ฉํ์ง ์๋ ์ด์ ๋ ๋ชจ๋ ๊ฐ์ฒด๊ฐ ํ๋์ ๋์คํฌ๋ฆฝํฐ ์ ์ ๊ณต์ ํ๊ธฐ ๋๋ฌธ์ ๋ณ๋๋ก ๊ด๋ฆฌํ ์ค๋ฒํค๋๊ฐ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
{
DescriptorLayoutBuilder builder;
builder.add_binding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
_gpuSceneDataDescriptorLayout = builder.build(_device, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
}
์ด์ draw_geometry()
ํจ์ ๋ด๋ถ์์ ๋งค ํ๋ ์๋ง๋ค ๋์คํฌ๋ฆฝํฐ ์
์ ์์ฑํ ๊ฒ์
๋๋ค. ํ๋ ์๋ง๋ค ๋์ ์ผ๋ก ์์ฑ๋๋ ์์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ์์ ๋ก ์ ๋ํผ ๋ฒํผ๋ ๋์ ์ผ๋ก ํ ๋นํ ์์ ์
๋๋ค. ์ค์ ๋ก๋ ์ด ๋ฒํผ๋ค์ FrameData ๊ตฌ์กฐ์ฒด์ ์บ์ฑํ๋ ๊ฒ์ด ๋ ๋ฐ๋์งํ์ง๋ง, ์ฌ๊ธฐ์๋ ๊ทธ ๊ณผ์ ์ ๋ณด์ฌ์ฃผ๊ธฐ ์ํ ๋ชฉ์ ์
๋๋ค. ๋์ ๋๋ก์ฐ๋ ๋ ๋ ํจ์ค๋ฅผ ์ฒ๋ฆฌํ ๋๋ ์ด์ ๊ฐ์ ๋ฐฉ์์ด ํ์ํ ์ ์์ต๋๋ค.
//allocate a new uniform buffer for the scene data
AllocatedBuffer gpuSceneDataBuffer = create_buffer(sizeof(GPUSceneData), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
//add it to the deletion queue of this frame so it gets deleted once its been used
get_current_frame()._deletionQueue.push_function([=, this]() {
destroy_buffer(gpuSceneDataBuffer);
});
//write the buffer
GPUSceneData* sceneUniformData = (GPUSceneData*)gpuSceneDataBuffer.allocation->GetMappedData();
*sceneUniformData = sceneData;
//create a descriptor set that binds that buffer and update it
VkDescriptorSet globalDescriptor = get_current_frame()._frameDescriptors.allocate(_device, _gpuSceneDataDescriptorLayout);
DescriptorWriter writer;
writer.write_buffer(0, gpuSceneDataBuffer.buffer, sizeof(GPUSceneData), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
writer.update_set(_device, globalDescriptor);
๋จผ์ CPU_TO_GPU ํ๋๊ทธ๋ฅผ ์ฌ์ฉํด CPU์์ ์ฝ๊ณ ์ธ ์ ์๋ ํ์ ์ ์ ๋ํผ ๋ฒํผ๋ฅผ ํ ๋นํฉ๋๋ค. ์ค์ ๋ก๋ CPU RAM์ ์์นํ ์ ์์ง๋ง, ์๋์ ๋ฐ์ดํฐ์ด๊ธฐ ๋๋ฌธ์ GPU๊ฐ ์บ์๋ก ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ฌ ๋ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ๋ฐ๋ผ์ ์ด๋ฌํ ๊ฒฝ์ฐ ์คํ ์ด์ง ๋ฒํผ๋ฅผ ํตํด GPU ์ ์ฉ ๋ฉ๋ชจ๋ฆฌ๋ก ์ ๋ก๋ํ๋ ๊ณผ์ ์ ์๋ตํ ์ ์์ต๋๋ค.
๊ทธํ ๋ฒํผ๋ฅผ ํ์ฌ ํ๋ ์์ ์ญ์ ํ์ ์ถ๊ฐํฉ๋๋ค. ์ด๋ ๋ฒํผ๋ฅผ ๋ค์ ํ๋ ์์ด ๋ ๋๋ง ๋ ํ ํ๊ดด๋๋๋ก ํ์ฌ GPU๊ฐ ํด๋น ๋ฒํผ์ ์ ๊ทผ์ ๋ง์น ์ถฉ๋ถํ ์๊ฐ์ ํ๋ณดํ ์ ์๊ฒ ํฉ๋๋ค. ํ ํ๋ ์์ ๋์ ์ผ๋ก ์์ฑ๋ ๋ชจ๋ ์์์ ์ด ์ญ์ ํ๋ฅผ ํตํด ์ ๋ฆฌ๋์ด์ผ ํฉ๋๋ค.
๋์คํฌ๋ฆฝํฐ ์ ์ _frameDescriptors๋ก๋ถํฐ ํ ๋นํฉ๋๋ค. ํด๋น ํ์ ๋งค ํ๋ ์ ๋ฆฌ์ ๋๋ฏ๋ก ์ญ์ ํ์ ๋น์ทํ๊ฒ ๋์ํ๋ฉฐ, GPU๊ฐ ์์ ์ฌ์ฉ์ ๋๋ด๋ ์์ ์ 2ํ๋ ์ ๋ค์ ์๋์ผ๋ก ์ญ์ ๋ฉ๋๋ค.
๊ทธ ๋ค์ ์๋ก ๋ง๋ ๋ฒํผ๋ฅผ ๋์คํฌ๋ฆฝํฐ ์ ์ ์์ฑํฉ๋๋ค. ์ด์ ์ ์ญ ๋์คํฌ๋ฆฝํฐ๊ฐ ๋ ๋๋ง์ ์ฌ์ฉํ ์ค๋น๊ฐ ๋์์ต๋๋ค. ์ง๊ธ์ ์ฌ ๋ฐ์ดํฐ ๋ฒํผ๋ฅผ ์ฌ์ฉํ๊ณ ์์ง ์์ง๋ง ์ดํ ํ์ํ ๊ฒ์ ๋๋ค.
๋ ๋๋ง์ ๊ณ์ํ๊ธฐ ์ ์ ํ ์ค์ณ๋ฅผ ์ค์ ํฉ์๋ค.
Next: Textures