Link

VkGraphicsPipelineCreateInfo

๊ทธ๋ž˜ํ”ฝ์Šค ํŒŒ์ดํ”„๋ผ์ธ์„ ๋งŒ๋“œ๋Š” ๊ณผ์ •์€ ์ปดํ“จํŠธ ํŒŒ์ดํ”„๋ผ์ธ์„ ๋งŒ๋“ค ๋•Œ ๋ณด๋‹ค ๊ฝค ๋งŽ์€ ์ž‘์—…์ด ์ถ”๊ฐ€๋กœ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ปดํ“จํŠธ ํŒŒ์ดํ”„๋ผ์ธ์—์„œ๋Š” ๋‹จ์ผ ์…ฐ์ด๋” ๋ชจ๋“ˆ๊ณผ ํŒŒ์ดํ”„๋ผ์ธ๋งŒ ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์–ด๋– ํ•œ ์ถ”์ƒ ๊ณ„์ธต๋„ ํ•„์š”๊ฐ€ ์—†์—ˆ์ง€๋งŒ, ๊ทธ๋ž˜ํ”ฝ์Šค ํŒŒ์ดํ”„๋ผ์ธ์€ ์„ค์ •ํ•ด์•ผ ํ•  ์˜ต์…˜์ด ์ƒ๋‹นํžˆ ๋งŽ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ๋‹จ์ˆœํ™”ํ•˜์ง€ ์•Š์œผ๋ฉด ์ƒ์„ฑ ๊ณผ์ •์ด ์ƒ๋‹นํžˆ ๋ณต์žกํ•ด์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์ด์œ ๋กœ, PipelineBuilder๋ผ๋Š” ๊ตฌ์กฐ์ฒด๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ด๋Ÿฌํ•œ ๋ชจ๋“  ์˜ต์…˜์„ ์ถ”์ ํ•˜๋ ค ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ตฌ์กฐ์ฒด๋Š” ๊ฐ€๋Šฅํ•œ ๋งŽ์€ ํ•ญ๋ชฉ์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์œ ์ง€ํ•˜๋ฉด์„œ, ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๊ธฐ๋Šฅ๋งŒ ํ™œ์„ฑํ™”/๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ๋‹จ์ˆœํ•œ ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” ์‚ฌ์šฉํ•  ์„ค์ •์ด ๋งŽ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ๋ณต์žก์„ฑ์„ ์ค„์ด๋Š” ๊ฒƒ์ด ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

ํŒŒ์ดํ”„๋ผ์ธ์˜ ์ด๋Ÿฌํ•œ ์˜ต์…˜ ์ค‘ ์ผ๋ถ€๋Š” ๋™์ ์œผ๋กœ ์„ค์ •๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ํŒŒ์ดํ”„๋ผ์ธ์„ ๋ฐ”์ธ๋”ฉํ•  ๋•Œ์™€ ๊ทธ๋ฆฌ๊ธฐ ๋ช…๋ น์„ ๊ธฐ๋กํ•  ๋•Œ ํ•ด๋‹น ์˜ต์…˜์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด viewport๋ฅผ ๋™์ ์œผ๋กœ ์ง€์ •ํ•  ์˜ˆ์ •์ธ๋ฐ, ๋งŒ์•ฝ ์ด๋ฅผ ๊ตฝ๋Š”(baked in) ๋ฐฉ์‹์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ๋ Œ๋”๋ง ํ•ด์ƒ๋„๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ์„ ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ํŒŒ์ดํ”„๋ผ์ธ์„ ์ƒ์„ฑํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

Builder๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์ „์—, ๋ฌด์—‡์„ ์ฑ„์›Œ์•ผ ํ•˜๋Š”์ง€ ๋จผ์ € ์‚ดํŽด๋ด…์‹œ๋‹ค. ์ปดํ“จํŠธ ํŒŒ์ดํ”„๋ผ์ธ์„ ์ƒ์„ฑํ•  ๋•Œ์™€ ๊ฐ™์ด ๊ทธ๋ž˜ํ”ฝ์Šค ํŒŒ์ดํ”„๋ผ์ธ์€ VkGraphicsPipelineCreateInfo๊ตฌ์กฐ์ฒด๋ฅผ ์ฑ„์›Œ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

typedef struct VkGraphicsPipelineCreateInfo {
    VkStructureType                                  sType;
    const void*                                      pNext;
    VkPipelineCreateFlags                            flags;
    uint32_t                                         stageCount;
    const VkPipelineShaderStageCreateInfo*           pStages;
    const VkPipelineVertexInputStateCreateInfo*      pVertexInputState;
    const VkPipelineInputAssemblyStateCreateInfo*    pInputAssemblyState;
    const VkPipelineTessellationStateCreateInfo*     pTessellationState;
    const VkPipelineViewportStateCreateInfo*         pViewportState;
    const VkPipelineRasterizationStateCreateInfo*    pRasterizationState;
    const VkPipelineMultisampleStateCreateInfo*      pMultisampleState;
    const VkPipelineDepthStencilStateCreateInfo*     pDepthStencilState;
    const VkPipelineColorBlendStateCreateInfo*       pColorBlendState;
    const VkPipelineDynamicStateCreateInfo*          pDynamicState;
    VkPipelineLayout                                 layout;
    VkRenderPass                                     renderPass;
    uint32_t                                         subpass;
    VkPipeline                                       basePipelineHandle;
    int32_t                                          basePipelineIndex;
} VkGraphicsPipelineCreateInfo;

๊ทธ๋ž˜ํ”ฝ์Šค ํŒŒ์ดํ”„๋ผ์ธ์˜ ๊ด€ํ•œ ์ •๋ณด๋Š” ๋‹ค์Œ ๋งํฌ์—์„œ ์„ธ๋ถ€ ์‚ฌํ•ญ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

stageCount์™€ pStages๋Š” ํŒŒ์ดํ”„๋ผ์ธ์˜ ๊ฐ ์…ฐ์ด๋” ๋‹จ๊ณ„์— ํ•ด๋‹นํ•˜๋Š” ์…ฐ์ด๋” ๋ชจ๋“ˆ ์ •๋ณด๋ฅผ ๋‹ด๋Š” VkPipelineShaderStageCreateInfo๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ์ •์  ์…ฐ์ด๋”์™€ ํ”„๋ž˜๊ทธ๋จผํŠธ ์…ฐ์ด๋”๋ฅผ ์ „๋‹ฌํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

VkPipelineVertexInputStateCreateInfo๋Š” ์ •์  ๋ฒ„ํผ์— ์‚ฌ์šฉํ•  ์ •์  ์†์„ฑ ์ž…๋ ฅ ๊ตฌ์„ฑ์„ ๋‹ด์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •ํ•˜๋ฉด ์ •์  ์…ฐ์ด๋”๋Š” ์ •์  ์†์„ฑ์„ ์ตœ์ ํ™”๋œ ๋ฐฉ์‹์œผ๋กœ ์ž…๋ ฅ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๋Š” ์ด๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋Š” ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์…ฐ์ด๋”์— ๋ฐ์ดํ„ฐ์˜ ๋ฐฐ์—ด์„ ์ง์ ‘ ์ „๋‹ฌํ•˜์—ฌ ์ธ๋ฑ์‹ฑํ•˜์—ฌ ์‚ฌ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์€ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๊ณ  ๋ฐ์ดํ„ฐ ์••์ถ•์ด ์ ์šฉ๋œ ๋” ๋ณต์žกํ•œ ์ •์  ํฌ๋งท์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์ •์  ํ’€๋ง(vertex pulling)์ด๋ผ๊ณ  ๋ถˆ๋ฆฌ๋ฉฐ, ๊ณ ์ • ํ•˜๋“œ์›จ์–ด ๋ฐฉ์‹์˜ ์ •์  ์ž…๋ ฅ๊ณผ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋”๋ผ๋„, ํ˜„๋Œ€ GPU์—์„œ๋Š” ๊ฑฐ์˜ ๋™์ผํ•œ ์„ฑ๋Šฅ์„ ๋ณด์ž…๋‹ˆ๋‹ค.

VkPipelineInputAssemblyStateCreateInfo๋Š” ์‚ผ๊ฐํ˜• ํ† ํด๋กœ์ง€๋ฅผ ๋‹ด์Šต๋‹ˆ๋‹ค. ์ด ๊ตฌ์กฐ์ฒด๋ฅผ ํ†ตํ•ด ํŒŒ์ดํ”„๋ผ์ธ์ด ์‚ผ๊ฐํ˜•, ์ , ์„  ์ค‘ ์–ด๋–ค ๋„ํ˜•์„ ๊ทธ๋ฆด ์ง€ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

VkPipelineTessellationStateCreateInfo๋Š” ๊ณ ์ • ๊ธฐ๋Šฅ ํ…Œ์…€๋ ˆ์ด์…˜์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ฏ€๋กœ null๋กœ ์„ค์ •ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

VkPipelineViewportStateCreateInfo๋Š” ํ”ฝ์…€์ด ๋ Œ๋”๋ง๋  ๋ทฐํฌํŠธ์˜ ์ •๋ณด๋ฅผ ๋‹ด์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํŒŒ์ดํ”„๋ผ์ธ์ด ์–ด๋–ค ์˜์—ญ์˜ ํ”ฝ์…€์— ๊ทธ๋ฆด์ง€๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋™์  ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋ฏ€๋กœ ์ด๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์„ค์ •ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

VkPipelineRasterizationStateCreateInfo๋Š” ์ •์  ์…ฐ์ด๋”์™€ ํ”„๋ž˜๊ทธ๋จผํŠธ ์…ฐ์ด๋” ๊ฐ„ ์‚ผ๊ฐํ˜•์„ ์–ด๋–ป๊ฒŒ ๋ž˜์Šคํ„ฐํ™”ํ• ์ง€์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋‹ด์Šต๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊นŠ์ด ๋ฐ”์ด์–ด์Šค(๊ทธ๋ฆผ์ž ๋ Œ๋”๋ง์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค), ์™€์ด์–ดํ”„๋ ˆ์ž„๊ณผ ์†”๋ฆฌ๋“œ ๋ Œ๋”๋ง ์ „ํ™˜, ๊ทธ๋ฆฌ๊ณ  ๋’ท๋ฉด ๋ Œ๋”๋ง ์—ฌ๋ถ€ ๋“ฑ์˜ ์˜ต์…˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

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

VkPipelineDepthStencilStateCreateInfo๋Š” ๊นŠ์ด ํ…Œ์ŠคํŠธ์™€ ์Šคํ…์‹ค ์„ค์ • ์ •๋ณด๋ฅผ ๋‹ด์Šต๋‹ˆ๋‹ค.

VkPipelineColorBlendStateCreateInfo๋Š” ๋ธ”๋ Œ๋”ฉ๊ณผ ์–ดํƒœ์น˜ ๋จผํŠธ ์“ฐ๊ธฐ ์„ค์ •์„ ๋‹ด์Šต๋‹ˆ๋‹ค. ํˆฌ๋ช…ํ•œ ์‚ผ๊ฐํ˜•์„ ๋ Œ๋”๋งํ•˜๊ฑฐ๋‚˜ ๋‹ค์–‘ํ•œ ๋ธ”๋ Œ๋”ฉ ์„ค์ •์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

VkPipelineDynamicStateCreateInfo๋Š” ๋™์  ์ƒํƒœ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ตฌ์กฐ์ฒด์ž…๋‹ˆ๋‹ค. Vulkan ํŒŒ์ดํ”„๋ผ์ธ์˜ ๊ฐ€์žฅ ํฐ ๋‹จ์  ์ค‘ ํ•˜๋‚˜๋Š” ํŒŒ์ดํ”„๋ผ์ธ ์„ค์ •์ด ์ƒ์„ฑ ์‹œ์— โ€œํ•˜๋“œ์ฝ”๋”ฉโ€ ๋œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๊นŠ์ด ํ…Œ์ŠคํŠธ๋ฅผ ์ผœ๊ฑฐ๋‚˜ ๋„๋Š” ๊ธฐ๋Šฅ์„ ์›ํ•œ๋‹ค๋ฉด 2๊ฐœ์˜ ํŒŒ์ดํ”„๋ผ์ธ์ด ํ•„์š”ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ทฐํฌํŠธ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ๋ Œ๋” ํƒ€๊ฒŸ์˜ ํฌ๊ธฐ๋ฅผ ๋ฐ”๊พธ๋ ค๋ฉด ๋ชจ๋“  ํŒŒ์ดํ”„๋ผ์ธ์„ ์žฌ๊ตฌ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ดํ”„๋ผ์ธ์„ ์ƒ์„ฑํ•˜๋Š” ๊ณผ์ •์€ ๋งค์šฐ ๋ฌด๊ฑฐ์šด ์ž‘์—…์ด๊ธฐ ๋•Œ๋ฌธ์— ํŒŒ์ดํ”„๋ผ์ธ์˜ ์ˆ˜๋ฅผ ๊ฐ€๋Šฅํ•œ ํ•œ ์ค„์ด๋Š” ๊ฒƒ์ด ์„ฑ๋Šฅ์ ์œผ๋กœ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ, Vulkan ํŒŒ์ดํ”„๋ผ์ธ์˜ ์ผ๋ถ€ ์ƒํƒœ๋Š” ๋™์ ์œผ๋กœ ์„ค์ •๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด ๋•Œ ์„ค์ •๋œ ์˜ต์…˜์€ ๋ Œ๋”๋ง ๋ช…๋ น์„ ๊ธฐ๋กํ•  ๋•Œ ๋Ÿฐํƒ€์ž„์— ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ๋™์  ์ƒํƒœ๋ฅผ ์ง€์›ํ•˜๋Š”์ง€๋Š” GPU ์ œ์กฐ์‚ฌ, ๋“œ๋ผ์ด๋ฒ„ ๋ฒ„์ „, ๊ธฐํƒ€ ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ GPU๊ฐ€ ๋ทฐํฌํŠธ์™€ ๊ฐ€์œ„ ์„ค์ •์— ๋Œ€ํ•œ ๋™์  ์ƒํƒœ๋ฅผ ์ง€์›ํ•˜๋ฏ€๋กœ, ์šฐ๋ฆฌ๋Š” ํ•ด๋‹น ํ•ญ๋ชฉ์„ ๋™์  ์ƒํƒœ๋กœ ์„ค์ •ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํŒŒ์ดํ”„๋ผ์ธ ์ƒ์„ฑ ์‹œ์ ์— ์ด๋ฏธ์ง€ ํ•ด์ƒ๋„๋ฅผ ๊ณ ์ •ํ•  ํ•„์š” ์—†์ด ์œ ์—ฐํ•˜๊ฒŒ ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

VkGraphicsPipelineCreateInfo๋Š” ์ปดํ“จํŠธ ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ์„ฑํ•  ๋•Œ์™€ ๋™์ผํ•œ VkPipelineLayout์„ ์ธ์ž๋กœ ๋ฐ›์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ VkRenderPass์™€ ์„œ๋ธŒํŒจ์Šค ์ธ๋ฑ์Šค๋„ ๋ฐ›์ง€๋งŒ, ๋™์  ๋ Œ๋”๋ง์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ๊ตฌ์„ฑํ•˜์ง€๋Š” ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฆ‰, VkRenderPass์™€ ๊ด€๋ จ๋œ ๋ชจ๋“  ์ ˆ์ฐจ๋ฅผ ๊ฑด๋„ˆ๋›ธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋Œ€์‹ , VkGraphicsPipelineCreateInfo๋ฅผ pNext์— ์—ฐ๊ฒฐํ•œ VkPipelineRenderingCreateInfo๋กœ ํ™•์žฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ตฌ์กฐ์ฒด๋Š” ํŒŒ์ดํ”„๋ผ์ธ์— ์‚ฌ์šฉํ•  ์–ดํƒœ์น˜๋จผํŠธ ํฌ๋งท์˜ ๋ชฉ๋ก์„ ๋‹ด์Šต๋‹ˆ๋‹ค.

์ด์ œ ๋นŒ๋” ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•ด๋ด…์‹œ๋‹ค. ๋ชจ๋“  ํŒŒ์ดํ”„๋ผ์ธ ์ฝ”๋“œ๋Š” vk_pipeline.s.h/cpp์— ์žˆ์Šต๋‹ˆ๋‹ค. ์ฑ•ํ„ฐ ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•˜๋ ค๋ฉด shared ํด๋”์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class PipelineBuilder {
public:
    std::vector<VkPipelineShaderStageCreateInfo> _shaderStages;
   
    VkPipelineInputAssemblyStateCreateInfo _inputAssembly;
    VkPipelineRasterizationStateCreateInfo _rasterizer;
    VkPipelineColorBlendAttachmentState _colorBlendAttachment;
    VkPipelineMultisampleStateCreateInfo _multisampling;
    VkPipelineLayout _pipelineLayout;
    VkPipelineDepthStencilStateCreateInfo _depthStencil;
    VkPipelineRenderingCreateInfo _renderInfo;
    VkFormat _colorAttachmentformat;

	PipelineBuilder(){ clear(); }

    void clear();

    VkPipeline build_pipeline(VkDevice device);
}

ํŒŒ์ดํ”„๋ผ์ธ ๋นŒ๋”๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ถ”์ ํ•ด์•ผ ํ•  ๋Œ€๋ถ€๋ถ„์˜ ์ƒํƒœ ์ •๋ณด์™€ ์ƒ‰์ƒ ์–ดํƒœ์น˜๋จผํŠธ ํฌ๋งท์˜ ๋ฐฐ์—ด, ๊ทธ๋ฆฌ๊ณ  ์…ฐ์ด๋” ๋‹จ๊ณ„ ์ •๋ณด๋ฅผ ๋‹ด์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ CreateInfo ๊ตฌ์กฐ์ฒด๋Š” build_pipeline() ํ•จ์ˆ˜์—์„œ ์ฑ„์›Œ์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค. clear()ํ•จ์ˆ˜๋Š” ๋ชจ๋“  ์ƒํƒœ๋ฅผ ์ดˆ๊ธฐ๊ฐ’ ํ˜น์€ ๋น„์–ด์žˆ๋Š” ์ƒํƒœ๋กœ ์„ค์ •ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŒŒ์ดํ”„๋ผ์ธ ๋นŒ๋”์˜ ์ƒ์„ฑ์ž๊ฐ€ ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๊ฒƒ์ด์ง€๋งŒ, ์ˆ˜๋™์ ์œผ๋กœ ์ดˆ๊ธฐํ™”๊ฐ€ ํ•„์š”ํ•  ๋•Œ๋ฅผ ๋Œ€๋น„ํ•ด ๋ณ„๋„์˜ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜๋กœ ๋ถ„๋ฆฌํ•ด๋‘๋Š” ํŽธ์ด ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋จผ์ € clear() ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•ด๋ด…์‹œ๋‹ค.

void PipelineBuilder::clear()
{
    // clear all of the structs we need back to 0 with their correct stype

    _inputAssembly = { .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };

    _rasterizer = { .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };

    _colorBlendAttachment = {};

    _multisampling = { .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };

    _pipelineLayout = {};

    _depthStencil = { .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };

    _renderInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO };

    _shaderStages.clear();
}

๋ชจ๋“  ๊ตฌ์กฐ์ฒด์˜ .sType์„ ์—ฌ๊ธฐ์„œ ๋ช…์‹œ์ ์œผ๋กœ ์„ค์ •ํ•ด์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‚˜๋จธ์ง€ ํ•„๋“œ๋“ค์€ 0์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” C++20 ๊ตฌ์กฐ์ฒด ์ดˆ๊ธฐํ™” ๋ฌธ๋ฒ•์„ ํ™œ์šฉํ•œ ๊ฒƒ์œผ๋กœ, ์ค‘๊ด„ํ˜ธ์—์„œ ๋ช…์‹œํ•˜์ง€ ์•Š์€ ํ•„๋“œ๋Š” ์ž๋™์œผ๋กœ 0์œผ๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค. Vulkan์˜ ๋Œ€๋ถ€๋ถ„์˜ Info ๊ตฌ์กฐ์ฒด๋Š” ๋ชจ๋“  ํ•„๋“œ๊ฐ€ 0์œผ๋กœ ์„ค์ •๋˜์–ด ์žˆ์–ด๋„ ์œ ํšจํ•œ ๊ธฐ๋ณธ ์ƒํƒœ๊ฐ€ ๋˜๋„๋ก ์„ค๊ณ„๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์€ ๋งค์šฐ ์ ์ ˆํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ build_pipeline ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•ฉ์‹œ๋‹ค. ๋จผ์ € ๊ตฌ์„ฑ๋˜์ง€ ์•Š์•„ ๋ˆ„๋ฝ๋œ info ๊ตฌ์กฐ์ฒด์ค‘ ์ผ๋ถ€๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

VkPipeline PipelineBuilder::build_pipeline(VkDevice device)
{
    // make viewport state from our stored viewport and scissor.
    // at the moment we wont support multiple viewports or scissors
    VkPipelineViewportStateCreateInfo viewportState = {};
    viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
    viewportState.pNext = nullptr;

    viewportState.viewportCount = 1;
    viewportState.scissorCount = 1;

    // setup dummy color blending. We arent using transparent objects yet
    // the blending is just "no blend", but we do write to the color attachment
    VkPipelineColorBlendStateCreateInfo colorBlending = {};
    colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
    colorBlending.pNext = nullptr;

    colorBlending.logicOpEnable = VK_FALSE;
    colorBlending.logicOp = VK_LOGIC_OP_COPY;
    colorBlending.attachmentCount = 1;
    colorBlending.pAttachments = &_colorBlendAttachment;

    // completely clear VertexInputStateCreateInfo, as we have no need for it
    VkPipelineVertexInputStateCreateInfo _vertexInputInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };

๋จผ์ € VkPipelineViewportStateCreateInfo๋ฅผ ๋ทฐํฌํŠธ ๊ฐœ์ˆ˜๋งŒ ์ฑ„์›๋‹ˆ๋‹ค. ๋™์  ๋ทฐํฌํŠธ ์ƒํƒœ์—์„œ๋Š” ๋ทฐํฌํŠธ๋‚˜ ์Šคํ…์‹ค ์˜ต์…˜์„ ์ฑ„์šธ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ ํ›„ VkPipelineColorBlendStateCreateInfo์—์„œ ๋ธ”๋ Œ๋”ฉ ๋กœ์ง์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ฑ„์›๋‹ˆ๋‹ค(์šฐ๋ฆฌ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค). ๊ทธ๋ฆฌ๊ณ  ํ•˜๋‚˜์˜ ์–ดํƒœ์น˜๋จผํŠธ ๋ธ”๋ Œ๋”ฉ ์ž‘์—…์„ ์œ„ํ•œ VkPipelineColorBlendAttachmentState๋ฅผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ์–ดํƒœ์น˜๋จผํŠธ ๋ Œ๋”๋ง๋งŒ์„ ์ง€์›ํ•  ๊ฒƒ์ด๋ฏ€๋กœ ์ด์ •๋„๋กœ ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ์–ดํƒœ์น˜๋จผํŠธ์— ๊ทธ๋ฆด ํ•„์š”๊ฐ€ ์žˆ๋‹ค๋ฉด VkPipelineColorBlendAttachmentState์˜ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•จ์ˆ˜๋ฅผ ๊ณ„์†ํ•ด VkGraphicsPipelineCreateInfo๋ฅผ ์ฑ„์›Œ๋ด…์‹œ๋‹ค.

    // build the actual pipeline
    // we now use all of the info structs we have been writing into into this one
    // to create the pipeline
    VkGraphicsPipelineCreateInfo pipelineInfo = { .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
    // connect the renderInfo to the pNext extension mechanism
    pipelineInfo.pNext = &_renderInfo;

    pipelineInfo.stageCount = (uint32_t)_shaderStages.size();
    pipelineInfo.pStages = _shaderStages.data();
    pipelineInfo.pVertexInputState = &_vertexInputInfo;
    pipelineInfo.pInputAssemblyState = &_inputAssembly;
    pipelineInfo.pViewportState = &viewportState;
    pipelineInfo.pRasterizationState = &_rasterizer;
    pipelineInfo.pMultisampleState = &_multisampling;
    pipelineInfo.pColorBlendState = &colorBlending;
    pipelineInfo.pDepthStencilState = &_depthStencil;
    pipelineInfo.layout = _pipelineLayout;

์ค€๋น„ํ•œ ๋ชจ๋“  ๊ตฌ์กฐ์ฒด๋ฅผ ํŒŒ์ดํ”„๋ผ์ธ ๋นŒ๋”์— ์—ฐ๊ฒฐํ•˜๊ณ  _renderInfo๋ฅผ pNext์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ๋™์  ์ƒํƒœ๋ฅผ ์„ค์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

    VkDynamicState state[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };

    VkPipelineDynamicStateCreateInfo dynamicInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
    dynamicInfo.pDynamicStates = &state[0];
    dynamicInfo.dynamicStateCount = 2;

    pipelineInfo.pDynamicState = &dynamicInfo;

๋™์  ์ƒํƒœ๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์€ VkPipelineDynamicStateCreateInfo๊ตฌ์กฐ์ฒด๋ฅผ VkDynamicState ์—ด๊ฑฐํ˜•์˜ ๋ฐฐ์—ด๋กœ ์ฑ„์šฐ๋Š” ๊ฒƒ์œผ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” 2๊ฐœ์˜ ๋™์  ์ƒํƒœ๋งŒ ์‚ฌ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๋ชจ๋“  ๊ณผ์ •์„ ๋งˆ์ณค์œผ๋ฏ€๋กœ, ์ƒ์„ฑํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด๋ด…์‹œ๋‹ค.

    // its easy to error out on create graphics pipeline, so we handle it a bit
    // better than the common VK_CHECK case
    VkPipeline newPipeline;
    if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo,
            nullptr, &newPipeline)
        != VK_SUCCESS) {
        fmt::println("failed to create pipeline");
        return VK_NULL_HANDLE; // failed to create graphics pipeline
    } else {
        return newPipeline;
    }

๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์œผ๋กœ ์ฃผ์š” ์ƒ์„ฑ ํ•จ์ˆ˜๋Š” ๋๋‚ฌ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์‹ค์ œ๋กœ ์˜ต์…˜๋“ค์„ ์ œ๋Œ€๋กœ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ๋Š” ๋ชจ๋“  ํŒŒ์ดํ”„๋ผ์ธ ์„ค์ •์ด ์‚ฌ์‹ค์ƒ ๋น„์–ด ์žˆ์–ด์„œ, ํ•„์š”ํ•œ ์˜ต์…˜์ด ๋ˆ„๋ฝ๋˜์–ด ๊ทธ๋Œ€๋กœ ์‹คํ–‰ํ•˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

void PipelineBuilder::set_shaders(VkShaderModule vertexShader, VkShaderModule fragmentShader)
{
    _shaderStages.clear();

    _shaderStages.push_back(
        vkinit::pipeline_shader_stage_create_info(VK_SHADER_STAGE_VERTEX_BIT, vertexShader));

    _shaderStages.push_back(
        vkinit::pipeline_shader_stage_create_info(VK_SHADER_STAGE_FRAGMENT_BIT, fragmentShader));
}

์ •์  ์…ฐ์ด๋”์™€ ํ”„๋ž˜๊ทธ๋จผํŠธ ์…ฐ์ด๋”๋ฅผ ์„ค์ •ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ด๋ด…์‹œ๋‹ค. ์ปดํ“จํŠธ ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ์„ฑํ•  ๋•Œ ์‚ฌ์šฉํ–ˆ๋˜ ๋ฐฉ์‹๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ์ด ์…ฐ์ด๋”๋“ค์„ ์ ์ ˆํ•œ ์ •๋ณด์™€ ํ•จ๊ป˜ _shaderStages ๋ฐฐ์—ด์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ์ž…๋ ฅ ํ† ํด๋กœ์ง€๋ฅผ ์„ค์ •ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

void PipelineBuilder::set_input_topology(VkPrimitiveTopology topology)
{
    _inputAssembly.topology = topology;
    // we are not going to use primitive restart on the entire tutorial so leave
    // it on false
    _inputAssembly.primitiveRestartEnable = VK_FALSE;
}

VkPrimitiveTopology๋Š” VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_PRIMITIVE_TOPOLOGY_POINT_LIST ๋“ฑ์˜ ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค. PrimitiveRestart๋Š” triangle strip์ด๋‚˜ line strip์— ์‚ฌ์šฉ๋˜์ง€๋งŒ ์—ฌ๊ธฐ์„œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ž˜์Šคํ„ฐํ™” ์ƒํƒœ๋Š” ๊ฝค ํฌ๋ฏ€๋กœ ์ด๋ฅผ ๋ช‡ ๊ฐœ์˜ ์˜ต์…˜์œผ๋กœ ๋‚˜๋ˆ„๊ฒ ์Šต๋‹ˆ๋‹ค.

void PipelineBuilder::set_polygon_mode(VkPolygonMode mode)
{
    _rasterizer.polygonMode = mode;
    _rasterizer.lineWidth = 1.f;
}

lineWidth๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ 1.f๋กœ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ํ›„ ์™€์ด์–ด ํ”„๋ ˆ์ž„, ์†”๋ฆฌ๋“œ ๋ Œ๋”๋ง, ๊ทธ๋ฆฌ๊ณ  ์  ๋ Œ๋”๋ง ์ค‘ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ๋ Œ๋”๋งํ• ์ง€๋ฅผ ์ œ์–ดํ•˜๋Š” polygon ๋ชจ๋“œ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

void PipelineBuilder::set_cull_mode(VkCullModeFlags cullMode, VkFrontFace frontFace)
{
    _rasterizer.cullMode = cullMode;
    _rasterizer.frontFace = frontFace;
}

์ปฌ๋ง ๋ชจ๋“œ๋Š” ์ „๋ฉด ๋ฐฉํ–ฅ๊ณผ ํ›„๋ฉด ์ปฌ๋ง์— ์‚ฌ์šฉํ•  ์ปฌ๋ง ๋ชจ๋“œ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

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

void PipelineBuilder::set_multisampling_none()
{
    _multisampling.sampleShadingEnable = VK_FALSE;
    // multisampling defaulted to no multisampling (1 sample per pixel)
    _multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
    _multisampling.minSampleShading = 1.0f;
    _multisampling.pSampleMask = nullptr;
    // no alpha to coverage either
    _multisampling.alphaToCoverageEnable = VK_FALSE;
    _multisampling.alphaToOneEnable = VK_FALSE;
}

๋‹ค์Œ์€ ๋ธ”๋ Œ๋”ฉ ๋ชจ๋“œ๋ฅผ ์œ„ํ•œ ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

void PipelineBuilder::disable_blending()
{
    // default write mask
    _colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
    // no blending
    _colorBlendAttachment.blendEnable = VK_FALSE;
}

disable_blending()ํ•จ์ˆ˜๋Š” blendEnable์„ false๋กœ ์„ค์ •ํ•˜์ง€๋งŒ, ์˜ฌ๋ฐ”๋ฅธ writeMask๋„ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ ๋” ๋งŽ์€ ๋ธ”๋ Œ๋”ฉ ๋ชจ๋“œ๋ฅผ ์ถ”ํ›„ ์ถ”๊ฐ€ํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ์„œ ์˜ฌ๋ฐ”๋ฅธ colorWriteMask๋ฅผ ์„ค์ •ํ•˜์—ฌ ํ”ฝ์…€ ์ถœ๋ ฅ์ด ์–ดํƒœ์น˜๋จผํŠธ๋กœ ์ •ํ™•ํžˆ ๊ธฐ๋ก๋˜๋„๋ก ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด์ œ ํฌ๋งท์„ ์—ฐ๊ฒฐํ•˜๊ณ , ๊นŠ์ด ํ…Œ์ŠคํŠธ์™€ ์ƒ‰์ƒ ์–ดํƒœ์น˜๋จผํŠธ๋ฅผ ์œ„ํ•œ ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

void PipelineBuilder::set_color_attachment_format(VkFormat format)
{
    _colorAttachmentformat = format;
    // connect the format to the renderInfo  structure
    _renderInfo.colorAttachmentCount = 1;
    _renderInfo.pColorAttachmentFormats = &_colorAttachmentformat;
}

void PipelineBuilder::set_depth_format(VkFormat format)
{
    _renderInfo.depthAttachmentFormat = format;
}

์ƒ‰์ƒ ์–ดํƒœ์น˜๋จผํŠธ์˜ ๊ฒฝ์šฐ ํŒŒ์ดํ”„๋ผ์ธ์ด ์ƒ‰์ƒ ์–ดํƒœ์น˜๋จผํŠธ ๋ฐฐ์—ด์„ ์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํฌ์ธํ„ฐ๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์—ฌ๋Ÿฌ ์ด๋ฏธ์ง€๋ฅผ ํ•œ๋ฒˆ์— ๊ทธ๋ฆฌ๋Š” ๋””ํผ๋“œ ๋ Œ๋”๋ง๊ณผ ๊ฐ™์€ ๊ณณ์—์„œ ์œ ์šฉํ•˜์ง€๋งŒ, ์ง€๊ธˆ์€ ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•˜๋‚˜์˜ ์ƒ‰์ƒ ํฌ๋งท๋งŒ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ, ๊นŠ์ด ํ…Œ์ŠคํŠธ ๋กœ์ง์„ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

void PipelineBuilder::disable_depthtest()
{
    _depthStencil.depthTestEnable = VK_FALSE;
    _depthStencil.depthWriteEnable = VK_FALSE;
    _depthStencil.depthCompareOp = VK_COMPARE_OP_NEVER;
    _depthStencil.depthBoundsTestEnable = VK_FALSE;
    _depthStencil.stencilTestEnable = VK_FALSE;
    _depthStencil.front = {};
    _depthStencil.back = {};
    _depthStencil.minDepthBounds = 0.f;
    _depthStencil.maxDepthBounds = 1.f;
}

ํŒŒ์ดํ”„๋ผ์ธ ๋นŒ๋”์˜ ๋ชจ๋“  ๊ธฐ๋ณธ ๊ธฐ๋Šฅ์ด ์ฑ„์›Œ์กŒ์œผ๋ฏ€๋กœ, ์ด์ œ ์‚ผ๊ฐํ˜•์„ ๊ทธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ์—๋Š” ์ •์  ์…ฐ์ด๋”์—์„œ ํ•˜๋“œ์ฝ”๋”ฉ๋œ ์ •์  ์œ„์น˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ์ถœ๋ ฅ์€ ๋‹จ์ƒ‰์œผ๋กœ ์„ค์ •ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค

๋‹ค์Œ์€ ์‚ฌ์šฉํ•  ์…ฐ์ด๋”์ž…๋‹ˆ๋‹ค.

colored_triangle.vert

#version 450

layout (location = 0) out vec3 outColor;

void main() 
{
	//const array of positions for the triangle
	const vec3 positions[3] = vec3[3](
		vec3(1.f,1.f, 0.0f),
		vec3(-1.f,1.f, 0.0f),
		vec3(0.f,-1.f, 0.0f)
	);

	//const array of colors for the triangle
	const vec3 colors[3] = vec3[3](
		vec3(1.0f, 0.0f, 0.0f), //red
		vec3(0.0f, 1.0f, 0.0f), //green
		vec3(00.f, 0.0f, 1.0f)  //blue
	);

	//output the position of each vertex
	gl_Position = vec4(positions[gl_VertexIndex], 1.0f);
	outColor = colors[gl_VertexIndex];
}

colored_triangle.frag

#version 450

//shader input
layout (location = 0) in vec3 inColor;

//output write
layout (location = 0) out vec4 outFragColor;

void main() 
{
	//return red
	outFragColor = vec4(inColor,1.0f);
}

์ •์  ์…ฐ์ด๋”์—๋Š” ํ•˜๋“œ์ฝ”๋”ฉ๋œ ์œ„์น˜ ๋ฐฐ์—ด์ด ์žˆ์œผ๋ฉฐ, gl_VertexIndex๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ๋ฐฐ์—ด์— ์ธ๋ฑ์‹ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์€ ์ปดํ“จํŠธ ์…ฐ์ด๋”์—์„œ์˜ LocalThreadID์™€ ์œ ์‚ฌํ•œ ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์ •์  ์…ฐ์ด๋”๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ์„œ๋กœ ๋‹ค๋ฅธ ์ธ๋ฑ์Šค๊ฐ€ ์ฃผ์–ด์ง€๋ฉฐ, ์ด๋ฅผ ํ™œ์šฉํ•ด ์ •์ ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ณ ์ • ํ•จ์ˆ˜ ๋ณ€์ˆ˜์ธ gl_Position์— ๊ฐ’์„ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. ๋ฐฐ์—ด์˜ ๊ธธ์ด๊ฐ€ 3์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋งŒ์•ฝ 3๊ฐœ ์ด์ƒ์˜ ์ •์ (1๊ฐœ ์ด์ƒ์˜ ์‚ผ๊ฐํ˜•)์„ ๋ Œ๋”๋งํ•œ๋‹ค๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ”„๋ž˜๊ทธ๋จผํŠธ ์…ฐ์ด๋”์—์„œ๋Š” layout = 0์— ์ถœ๋ ฅ๊ฐ’์„ ์„ ์–ธํ•˜๊ณ (์ด๋Š” ๋ Œ๋”ํŒจ์Šค์—์„œ ์„ค์ •ํ•œ ์–ดํƒœ์น˜๋จผํŠธ์— ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค), ๋‹จ์ˆœํžˆ ํ•˜๋“œ์ฝ”๋”ฉ๋œ ๋นจ๊ฐ„์ƒ‰์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ ์‚ผ๊ฐํ˜•์„ ๊ทธ๋ฆด ๋•Œ ํ•„์š”ํ•œ ํŒŒ์ดํ”„๋ผ์ธ๊ณผ ํŒŒ์ดํ”„๋ผ์ธ ๋ ˆ์ด์•„์›ƒ์„ ๋งŒ๋“ค๊ฒ ์Šต๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ์…ฐ์ด๋” ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ–ˆ์œผ๋ฏ€๋กœ CMake ํ”„๋กœ์ ํŠธ๋ฅผ ์žฌ๋นŒ๋“œํ•˜์—ฌ Shaders ํƒ€๊ฒŸ์„ ๋นŒ๋“œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

VulkanEngine ํด๋ž˜์Šค์— init_triangle_pipeline()ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ํŒŒ์ดํ”„๋ผ์ธ๊ณผ ํŒŒ์ดํ”„๋ผ์ธ ๋ ˆ์ด์•„์›ƒ์„ ๋‹ด๋Š” ๋ฉค๋ฒ„๋„ ์ถ”๊ฐ€ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

VkPipelineLayout _trianglePipelineLayout;
VkPipeline _trianglePipeline;

void init_triangle_pipeline();

init_triangle_pipeline()์„ init_pipelines()ํ•จ์ˆ˜์—์„œ ํ˜ธ์ถœํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด์ œ ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ปดํ“จํŠธ ์…ฐ์ด๋”์—์„œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ•จ์ˆ˜๋ฅผ ๋‘ ์…ฐ์ด๋”๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ฒƒ์œผ๋กœ ์‹œ์ž‘ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์ด๋ฒˆ์—๋Š” ๋” ๋งŽ์€ ์…ฐ์ด๋”๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

	VkShaderModule triangleFragShader;
	if (!vkutil::load_shader_module("../../shaders/colored_triangle.frag.spv", _device, &triangleFragShader)) {
		fmt::print("Error when building the triangle fragment shader module");
	}
	else {
		fmt::print("Triangle fragment shader succesfully loaded");
	}

	VkShaderModule triangleVertexShader;
	if (!vkutil::load_shader_module("../../shaders/colored_triangle.vert.spv", _device, &triangleVertexShader)) {
		fmt::print("Error when building the triangle vertex shader module");
	}
	else {
		fmt::print("Triangle vertex shader succesfully loaded");
	}
	
	//build the pipeline layout that controls the inputs/outputs of the shader
	//we are not using descriptor sets or other systems yet, so no need to use anything other than empty default
	VkPipelineLayoutCreateInfo pipeline_layout_info = vkinit::pipeline_layout_create_info();
	VK_CHECK(vkCreatePipelineLayout(_device, &pipeline_layout_info, nullptr, &_trianglePipelineLayout));

๋˜ํ•œ ํŒŒ์ดํ”„๋ผ์ธ ๋ ˆ์ด์•„์›ƒ๋„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด์ „์˜ ์ปดํ“จํŠธ ์…ฐ์ด๋”์™€๋Š” ๋‹ฌ๋ฆฌ, ์ด๋ฒˆ์—๋Š” ํ‘ธ์‹œ ์ƒ์ˆ˜๋‚˜ ๋””์Šคํฌ๋ฆฝํ„ฐ ๋ฐ”์ธ๋”ฉ์ด ์ „ํ˜€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์™„์ „ํžˆ ๋น„์–ด์žˆ๋Š” ๋ ˆ์ด์•„์›ƒ์ž…๋‹ˆ๋‹ค.

์ด์ œ ์•ž์„œ ๋งŒ๋“  PipelineBuilder๋ฅผ ์‚ฌ์šฉํ•ด ํŒŒ์ดํ”„๋ผ์ธ์„ ์ƒ์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

	PipelineBuilder pipelineBuilder;

	//use the triangle layout we created
	pipelineBuilder._pipelineLayout = _trianglePipelineLayout;
	//connecting the vertex and pixel shaders to the pipeline
	pipelineBuilder.set_shaders(triangleVertexShader, triangleFragShader);
	//it will draw triangles
	pipelineBuilder.set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
	//filled triangles
	pipelineBuilder.set_polygon_mode(VK_POLYGON_MODE_FILL);
	//no backface culling
	pipelineBuilder.set_cull_mode(VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE);
	//no multisampling
	pipelineBuilder.set_multisampling_none();
	//no blending
	pipelineBuilder.disable_blending();
	//no depth testing
	pipelineBuilder.disable_depthtest();

	//connect the image format we will draw into, from draw image
	pipelineBuilder.set_color_attachment_format(_drawImage.imageFormat);
	pipelineBuilder.set_depth_format(VK_FORMAT_UNDEFINED);

	//finally build the pipeline
	_trianglePipeline = pipelineBuilder.build_pipeline(_device);

	//clean structures
	vkDestroyShaderModule(_device, triangleFragShader, nullptr);
	vkDestroyShaderModule(_device, triangleVertexShader, nullptr);

	_mainDeletionQueue.push_function([&]() {
		vkDestroyPipelineLayout(_device, _trianglePipelineLayout, nullptr);
		vkDestroyPipeline(_device, _trianglePipeline, nullptr);
	});

ํŒŒ์ดํ”„๋ผ์ธ์ด ์ƒ์„ฑ๋˜์—ˆ์œผ๋ฏ€๋กœ, ๋งค ํ”„๋ ˆ์ž„๋งˆ๋‹ค ์ƒ์„ฑ๋˜๋Š” ์ปค๋งจ๋“œ ๋ฒ„ํผ์—์„œ ์‚ผ๊ฐํ˜•์„ ๊ทธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ์‚ฌ์šฉ๋œ ์ปดํ“จํŠธ ์…ฐ์ด๋”๋Š” GENERAL ๋ ˆ์ด์•„์›ƒ์˜ ์ด๋ฏธ์ง€์— ์ž‘์„ฑํ•ด์•ผ ํ–ˆ์ง€๋งŒ, ๋„ํ˜•(geometry) ๋ Œ๋”๋ง์„ ์ˆ˜ํ–‰ํ•  ๋•Œ์—๋Š” COLOR_ATTACHMENT_OPTIMAL์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜ํ”ฝ์Šค ํŒŒ์ดํ”„๋ผ์ธ์—์„œ GENERAL ๋ ˆ์ด์•„์›ƒ์— ๊ทธ๋ฆด์ˆ˜๋Š” ์žˆ์ง€๋งŒ ์„ฑ๋Šฅ์ด ๋‚ฎ๊ณ , ๊ฒ€์ฆ ๋ ˆ์ด์–ด๊ฐ€ ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ทธ๋ž˜ํ”ฝ ๋ช…๋ น์„ ๋‹ด๊ธฐ ์œ„ํ•ด ์ƒˆ๋กœ์šด ํ•จ์ˆ˜ draw_geometry()๋ฅผ ๋งŒ๋“ค๊ณ , ๋จผ์ € ๋ Œ๋”๋ง ๋ฃจํ”„๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

	VK_CHECK(vkBeginCommandBuffer(cmd, &cmdBeginInfo));

	// transition our main draw image into general layout so we can write into it
	// we will overwrite it all so we dont care about what was the older layout
	vkutil::transition_image(cmd, _drawImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);

	draw_background(cmd);

	vkutil::transition_image(cmd, _drawImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);

	draw_geometry(cmd);

	//transtion the draw image and the swapchain image into their correct transfer layouts
	vkutil::transition_image(cmd, _drawImage.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
	vkutil::transition_image(cmd, _swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);

์ด์ œ draw_geometry ํ•จ์ˆ˜๋ฅผ ์ฑ„์›์‹œ๋‹ค.

void VulkanEngine::draw_geometry(VkCommandBuffer cmd)
{
	//begin a render pass  connected to our draw image
	VkRenderingAttachmentInfo colorAttachment = vkinit::attachment_info(_drawImage.imageView, nullptr, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);

	VkRenderingInfo renderInfo = vkinit::rendering_info(_drawExtent, &colorAttachment, nullptr);
	vkCmdBeginRendering(cmd, &renderInfo);

	vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _trianglePipeline);

	//set dynamic viewport and scissor
	VkViewport viewport = {};
	viewport.x = 0;
	viewport.y = 0;
	viewport.width = _drawExtent.width;
	viewport.height = _drawExtent.height;
	viewport.minDepth = 0.f;
	viewport.maxDepth = 1.f;

	vkCmdSetViewport(cmd, 0, 1, &viewport);

	VkRect2D scissor = {};
	scissor.offset.x = 0;
	scissor.offset.y = 0;
	scissor.extent.width = _drawExtent.width;
	scissor.extent.height = _drawExtent.height;

	vkCmdSetScissor(cmd, 0, 1, &scissor);

	//launch a draw command to draw 3 vertices
	vkCmdDraw(cmd, 3, 1, 0, 0);

	vkCmdEndRendering(cmd);
}

์‚ผ๊ฐํ˜•์„ ๊ทธ๋ฆฌ๊ธฐ ์œ„ํ•ด vkCmdBeginRendering์„ ํ˜ธ์ถœํ•ด ๋ Œ๋”ํŒจ์Šค๋ฅผ ์‹œ์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ง€๋‚œ ์ฑ•ํ„ฐ์—์„œ์˜ ImGui์—์„œ์™€ ๋™์ผํ•˜์ง€๋งŒ, ์ด๋ฒˆ์—๋Š” ์Šค์™‘์ฒด์ธ ์ด๋ฏธ์ง€๊ฐ€ ์•„๋‹ˆ๋ผ _drawImage๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.

vkCmdBindPipeline๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ, ์ด์ „์ฒ˜๋Ÿผ VK_PIPELINE_BIND_POINT_COMPUTE์ด ์•„๋‹ˆ๋ผ VK_PIPELINE_BIND_POINT_GRAPHICS๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ ๋ทฐํฌํŠธ์™€ ๊ฐ€์œ„๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํŒŒ์ดํ”„๋ผ์ธ ์ƒ์„ฑ ์‹œ ๋™์  ํŒŒ์ดํ”„๋ผ์ธ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•„์ˆ˜์ ์œผ๋กœ ์„ค์ •ํ•ด์•ผ ํ•˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ์„ค์ •์ด ์™„๋ฃŒ๋˜๋ฉด vkCmdDraw๋ฅผ ํ˜ธ์ถœํ•ด ์‚ผ๊ฐํ˜•์„ ๊ทธ๋ฆด ์ˆ˜ ์žˆ๊ณ , ์ดํ›„ ๋ Œ๋”ํŒจ์Šค๋ฅผ ์ข…๋ฃŒํ•˜์—ฌ ๊ทธ๋ฆฌ๊ธฐ ์ž‘์—…์„ ๋งˆ๋ฌด๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์‹œ์ ์—์„œ ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•œ๋‹ค๋ฉด ์ปดํ“จํŠธ ์…ฐ์ด๋”๋กœ ๊ทธ๋ฆฐ ๋ฐฐ๊ฒฝ ์œ„์— ์‚ผ๊ฐํ˜•์ด ๋ Œ๋”๋ง ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

triangle

Next: Mesh buffers