1. 程式人生 > >Vulkan Cookbook 第四章 13 將資料從緩衝區複製到影象

Vulkan Cookbook 第四章 13 將資料從緩衝區複製到影象

將資料從緩衝區複製到影象

譯者注:示例程式碼點選此處

對於影象,我們可以繫結從不同記憶體型別分配的記憶體物件。但我們只能從的應用程式直接對映和更新主機可見記憶體。當想要更新使用裝置本地記憶體的影象記憶體時。我們需要從緩衝區中複製資料。

怎麼做...

1.獲取命令緩衝區的控制代碼並將其儲存在名為command_buffer的VkCommandBuffer型別變數中。確保命令緩衝區已處於記錄狀態(請參閱第3章,命令緩衝區和同步中的開始命令緩衝區記錄操作內容)。
2.獲取將從中複製資料的緩衝區。將其控制代碼儲存在名為source_buffer的VkBuffer型別變數中。
3.獲取要複製資料的影象。使用名為destination_image的VkImage型別的變量表示此影象。
4.建立一個名為image_layout的VkImageLayout型別的變數,其中將儲存影象的當前佈局。
5.建立名為regions的std::vector<VkBufferImageCopy>型別變數。元素數量是我們希望複製的所有區域數量。為每個元素成員指定以下值:
    ·bufferOffset從緩衝區記憶體的起始處偏移。
    ·bufferRowLength表示緩衝區單行的資料長度,如果資料緊密打包(根據目標影象大小)則為0值。
    ·bufferImageHeight表示儲存在緩衝區中的虛構影象的高度,如果緩衝區的資料緊密打包(根據目標影象大小)則0值。
    ·使用一下值初始化imageSubresource成員:
        ·aspectMask為影象方面(顏色,深度或模板)
        ·mipLevel為更新的mipmap級別的編號(索引)
        ·baseArrayLayer為更新的第一個陣列層的編號
        ·layerCount為更新的陣列層數
        ·imageOffset為更新的影象子區域的初始化偏移(以紋素為單位)
        ·imageExtent為影象的大小(尺寸)
6.呼叫vkCmdCopyBufferToImage( command_buffer, source_buffer, destination_image, image_layout, static_cast<uint32_t>(regions.size()), &regions[0] )。使用command_buffer、source_buffer、destination_image、image_layout變數、regions向量中的元素數量和指向它的第一個元素的指標。

這個怎麼運作...

在緩衝區和影象之間複製資料是通過命令緩衝區完成的,如下操作:

if( regions.size() > 0 ) {
      vkCmdCopyBufferToImage( command_buffer, source_buffer, destination_image, image_layout, static_cast<uint32_t>(regions.size()), regions.data() );
}

我們需要知道影象資料如何在緩衝區內佈局,以便正確上傳影象的記憶體。需要提供一個記憶體偏移量(從緩衝區記憶體的開頭)、資料行的長度以及緩衝區中的資料高度。這准許驅動正確地定址儲存器並將緩衝區的記憶體複製到影象中。我們還可以為長度和高度提供0,這意味著緩衝區包含緊密打包的資料,它對應於目標影象的尺寸。

我們還需要提供有關資料傳輸操作目標的資訊。這涉及定義x,y和z維度的影象原點(從紋理的左上角偏移),資料將被複制到的mipmap級別和陣列的基礎層以及將要覆蓋的層數、還需指定目標影象的尺寸。

所有前面的引數都是通過VkBufferImageCopy元素陣列指定的。我們可以同時提供許多區域並複製不連續的記憶體範圍。

在具有由物理裝置公開的多種不同記憶體型別的硬體體系系統結構上,建議對呈現期間使用的資源使用裝置本地專用記憶體。這種記憶體通常比主機可見記憶體更快。主機可見記憶體應該只用於暫存資源,這些資源用於CPU(我們的應用程式)上傳資料或下載資料。

在只有一個記憶體型別(裝置本地和主機可見)的體系結構中,我們不需要為資料上傳而煩惱中間階段資源。但是,所提出的方法仍然有效,並且可以跨不同的執行環境統一應用程式的行為,這可以使我們的應用程式的維護更容易。

在這兩種情況下,可以使用它來進行裝置-本地記憶體傳輸資料,裝置-本地記憶體(通常)無法對映,這是通過本節內容中的描述的複製操作實現的。我們都可以輕鬆轉移殘存記憶體的資源並在應用程式中訪問它。

提示:必須使用VK_BUFFER_USAGE_TRANSFER_SRC_BIT用法建立可以複製資料的緩衝區。
           必須使用VK_BUFFER_USAGE_TRANSFER_DST_BIT用法建立我們傳輸資料的影象。在傳輸操作之前還需要將影象佈局轉換為VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL。

在我們將資料傳輸到影象之前,必須改變其記憶體佈局,只能將資料複製到當前記憶體佈局為VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL的影象。我們也可以使用VK_IMAGE_LAYOUT_GENERAL佈局,但由於效能較低,不建議使用。

因此,在我們將資料複製到影象之前,應該設定一個記憶體屏障,將影象的記憶體訪問型別應從當前進行的型別更改為VK_ACCESS_TRANSFER_WRITE_BIT。還應執行從當前佈局到VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL佈局的佈局轉換。在完成將資料複製到影象並且完成需要做的目的之後,我們應該設定另一個記憶體屏障,這次,我們應該從記憶體訪問型別從VK_ACCESS_TRANSFER_WRITE_BIT更改為與使用影象目的相對應的訪問型別。還應該將影象佈局從VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL轉換為與影象的下一次使用的相容佈局(請參閱設定影象記憶體屏障內容)。沒有這些屏障,不僅資料傳輸操作可能無效,而且資料可能在影象上執行的其他操作中不可見。

如果作為資料來源的緩衝區用於其他目的,我們還應為其設定記憶體屏障,並在傳輸操作之前和之後執行類似的記憶體訪問型別更改。但由於緩衝區是資料來源,我們在第一個屏障中設定VK_ACCESS_TRANSFER_READ_BIT訪問型別。它可以用改變影象引數的相同管線屏障來完成。有關更多詳細資訊請參閱設定緩衝區記憶體屏障內容。