Link

์ด์ œ ํ…์Šค์ณ๋ฅผ ์ง€์›ํ•˜๊ณ  ๋ณต์žก๋„๊ฐ€ ํฌ๊ฒŒ ์ฆ๊ฐ€ํ•จ์— ๋”ฐ๋ผ ์—”์ง„ ์ถ”์ƒํ™”๋ฅผ ํ™•์žฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ๋””์Šคํฌ๋ฆฝํ„ฐ ์…‹์— ๋Œ€ํ•ด ๋” ๋‚˜์€ ์ถ”์ƒํ™”๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

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