Setup

在我們完成管線的創(chuàng)建工作,我們接下來(lái)需要告訴Vulkan渲染時(shí)候使用的framebuffer幀緩沖區(qū)附件相關(guān)信息。我們需要指定多少個(gè)顏色和深度緩沖區(qū)將會(huì)被使用,指定多少個(gè)采樣器及如何在整個(gè)渲染操作中處理它們。所有的這些信息都被封裝在一個(gè)叫做render pass的對(duì)象中,我們新添加一個(gè)createRenderPass函數(shù)。在initVulkan函數(shù)中確保createGraphicsPipeline調(diào)用之前,調(diào)用它。

 

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

void initVulkan() {
    createInstance();
    setupDebugCallback();
    createSurface();
    pickPhysicalDevice();
    createLogicalDevice();
    createSwapChain();
    createImageViews();
    createRenderPass();
    createGraphicsPipeline();
}

...void createRenderPass() {

}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

 Attachment description


在教程中僅有一個(gè)顏色緩沖區(qū)附件被交換鏈中的一個(gè)圖像所代表。

void createRenderPass() {
    VkAttachmentDescription colorAttachment = {};
    colorAttachment.format = swapChainImageFormat;
    colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
}

format是顏色附件的格式,它應(yīng)該與交換鏈中圖像的格式相匹配,同時(shí)我們不會(huì)做任何多重采樣的工作,所以采樣器設(shè)置為1。

colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;

loadOpstoreOp決定了渲染前和渲染后數(shù)據(jù)在對(duì)應(yīng)附件的操作行為。有兩種選擇針對(duì)loadOp:

  • VK_ATTACHMENT_LOAD_OP_LOAD: 保存已經(jīng)存在于當(dāng)前附件的內(nèi)容

  • VK_ATTACHMENT_LOAD_OP_CLEAR: 起始階段以一個(gè)常量清理附件內(nèi)容

  • VK_ATTACHMENT_LOAD_OP_DONT_CARE: 存在的內(nèi)容未定義,忽略它們

我們要做的是使用清理操作來(lái)清理幀緩沖區(qū)framebuffer為黑色,在繪制任何新的幀之前。同時(shí)有兩個(gè)選擇針對(duì)storeOp:

  • VK_ATTACHMENT_STORE_OP_TORE: 渲染的內(nèi)容會(huì)存儲(chǔ)在內(nèi)容,并在過(guò)后讀取

  • VK_ATTACHMENT_STORE_OP_DONT_CARE: 幀緩沖區(qū)的內(nèi)容在渲染操作完畢后設(shè)置為undefined

我們要做的是渲染一個(gè)三角形在屏幕上,所以我們選擇存儲(chǔ)操作。

colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;

loadOpstoreOp應(yīng)用在顏色和深度數(shù)據(jù),同時(shí)stencilLoadOp / stencilStoreOp應(yīng)用在模版數(shù)據(jù)。我們的應(yīng)用程序不會(huì)做任何模版緩沖區(qū)的操作,所以它的loading和storing無(wú)關(guān)緊要。

colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;

紋理和幀緩沖區(qū)在Vulkan中通常用VkImage 對(duì)象配以某種像素格式來(lái)代表。但是像素在內(nèi)存中的布局可以基于預(yù)要對(duì)image圖像進(jìn)行的操作發(fā)生內(nèi)存布局的變化。

 

一些常用的布局:

  • VK_IMAGE_LAYOUT_COLOR_ATTACHMET_OPTIMAL: 圖像作為顏色附件

  • VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: 圖像在交換鏈中被呈現(xiàn)

  • VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: 圖像作為目標(biāo),用于內(nèi)存COPY操作

 

我們會(huì)深入討論這些內(nèi)容在紋理章節(jié),現(xiàn)在最重要的是為需要轉(zhuǎn)變的圖像指定合適的layout布局進(jìn)行操作。

 大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

initialLayout指定圖像在開(kāi)始進(jìn)入渲染通道render pass前將要使用的布局結(jié)構(gòu)。finalLayout指定當(dāng)渲染通道結(jié)束自動(dòng)轉(zhuǎn)變時(shí)使用的布局。使用VK_IMAGE_LAYOUT_UNDEFINED設(shè)置initialLayout,意為不關(guān)心圖像之前的布局。特殊值表明圖像的內(nèi)容不確定會(huì)被保留,但是這并不總要,因?yàn)闊o(wú)論如何我們都要清理它。我們希望圖像渲染完畢后使用交換鏈進(jìn)行呈現(xiàn),這就解釋了為什么finalLayout要設(shè)置為VK_IMAGE_LAYOUT_PRESENT_SRC_KHR

 

如果沒(méi)有搞清楚布局存在的意義,進(jìn)一步解釋layout請(qǐng)看如下圖示:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

一般意義上,我們理解CPU進(jìn)行內(nèi)存中的數(shù)據(jù)讀寫(xiě)往往都是線性排序的linear memory layout,可以看到AB與CD作為來(lái)個(gè)連續(xù)的行來(lái)進(jìn)行讀取。但是在很多時(shí)候?qū)τ谙袼丶y理數(shù)據(jù)的操作是非線性連續(xù)的,這種情景更多發(fā)生在GPU操作中,所以GPU硬件更多的支持基于(Tiled)平鋪的或者成為最佳的內(nèi)存布局結(jié)構(gòu),來(lái)提降低GPU處理數(shù)據(jù)的開(kāi)銷(xiāo)。

 

所以從CPU linear layout 內(nèi)存數(shù)據(jù) 到 GPU optimal layout 顯存數(shù)據(jù)的讀寫(xiě) 往返之間存在數(shù)據(jù)存儲(chǔ)格式的優(yōu)化轉(zhuǎn)變步驟。

Subpasses and attachment references


一個(gè)單獨(dú)的渲染通道可以由多個(gè)子通道組成。子通道是渲染操作的一個(gè)序列。子通道作用與后續(xù)的渲染操作,并依賴之前渲染通道輸出到幀緩沖區(qū)的內(nèi)容。比如說(shuō)后處理效果的序列通常每一步都依賴之前的操作。如果將這些渲染操作分組到一個(gè)渲染通道中,通過(guò)Vulkan將通道中的渲染操作進(jìn)行重排序,可以節(jié)省內(nèi)存從而獲得更好的性能。對(duì)于我們要繪制的三角形,我們只需要一個(gè)子通道。

 

每個(gè)子通道引用一個(gè)或者多個(gè)之前使用結(jié)構(gòu)體描述的附件。這些引用本身就是VkAttachmentReference結(jié)構(gòu)體:

VkAttachmentReference colorAttachmentRef = {};
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

attachment附件參數(shù)通過(guò)附件描述符集合中的索引來(lái)持有。我們的集合是由一個(gè)VkAttachmentDesription組成的,所以它的索引為0。layout為附件指定子通道在持有引用時(shí)候的layout。當(dāng)子通道開(kāi)始的時(shí)候Vulkan會(huì)自動(dòng)轉(zhuǎn)變附件到這個(gè)lyaout。因?yàn)閕我們期望附件起到顏色緩沖區(qū)的作用,layout設(shè)置為VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL會(huì)給我們最好的性能。

 

子通道使用VkSubpassDescription結(jié)構(gòu)體描述:

VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;

Vulkan在未來(lái)可能會(huì)支持關(guān)于compute subpasses的功能,所以在這里我們明確指定graphics subpass圖形子通道。下一步為它指定顏色附件的引用:

subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;

附件在數(shù)組中的索引直接從片段著色器引用,其 layout(location = 0) out vec4 outColor 指令!

 

可以被子通道引用的附件類(lèi)型如下:

  • pInputAttachments: 附件從著色器中讀取

  • pResolveAttachments: 附件用于顏色附件的多重采樣

  • pDepthStencilAttachment: 附件用于深度和模版數(shù)據(jù)

  • pPreserveAttachments: 附件不被子通道使用,但是數(shù)據(jù)被保存

Render pass


現(xiàn)在附件和基本的子通道已經(jīng)介紹過(guò)了,我們可以創(chuàng)建渲染通道了。首先新建一個(gè)類(lèi)成員變量持有VkRenderPass對(duì)象,該變量在pipelineLayout上定義:

VkRenderPass renderPass;
VkPipelineLayout pipelineLayout;

渲染通道對(duì)象創(chuàng)建通過(guò)填充VkRenderPassCreateInfo結(jié)構(gòu)體,并配合相關(guān)附件和子通道來(lái)完成。VkAttachmentReference對(duì)象引用附件數(shù)組。

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = 1;
renderPassInfo.pAttachments = &colorAttachment;
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {    throw std::runtime_error("failed to create render pass!");
}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

就像pipeline layout一樣,渲染通道在整個(gè)程序生命周期內(nèi)都被使用,所以需要在退出階段進(jìn)行清理:

void cleanup() {
    vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
    vkDestroyRenderPass(device, renderPass, nullptr);
    ...
}

這看起來(lái)很多工作量,但是在下一章節(jié)我們會(huì)把所有的組件整合起來(lái),創(chuàng)建最終的圖形管線對(duì)象。

http://www.cnblogs.com/heitao/p/6979494.html