天天看點

Vulkan程式設計指南翻譯 第二章 第二節 資源

第二章 記憶體與資源 第二節 資源

Vulkan操縱數組。與之相比,其他東西重要性皆次之。資料被存儲在resources中,resource存放在記憶體硬體中。Vulkan有兩種基礎的資源:buffers 與 images。Buffer是一塊兒簡單的、連續的資料,可以用來存儲任何東西—資料結構,原生數組,甚至圖像資料,你應當選擇buffer。另一方面,Images,是結構化的,擁有類型資訊,可以是多元的,自己也可組成數組,可以支援進階的讀寫操作。

兩種類型的resource都是通過兩個步驟完成構造的:一,建立resource,然後放在記憶體中。這麼做的原因是允許應用程式自己來管理記憶體。記憶體管理比較複雜,由驅動來做就會比較困難,也許一個程式中工作正常,在其他的程式中就不工作。是以,應該是由應用程式來做記憶體管理,而不是驅動。例如,一個應用程式可以使用數量很少但資料量很大的資源,使用單獨的記憶體配置設定器的管理政策,讓它們常駐記憶體,然而,其他的程式可能需要不斷的建立并銷毀小資料量的資源。

即使images資料結構比較複雜,它被建立的過程和buffes類似。本節将先講解buffer的建立,後講解images。

Buffres

Buffers是Vulkan中最簡單但使用非常廣泛的資源類型。它通常被用來存儲連續的結構化的或非結構化的資料,在記憶體中可以有格式或者原生的bytes。當我們将讨論到這些話題時,就會降到buffers對象的各種使用方式。建立buffer對象,需調用vkCreateBuffer(),原型如下:

VkResult vkCreateBuffer (

VkDevice  device,

const VkBufferCreateInfo*  pCreateInfo,

const VkAllocationCallbacks* pAllocator,

VkBuffer*  pBuffer); 

如同Vulkan中大多數函數,它有許多個參數,這些參數被打包進一個資料結構中,通過指針傳到Vulkan。這裡,pCreateInfo參數是指向一個instance的VkBufferCreateInfo成員的指針,它的定義如下:

typedef struct VkBufferCreateInfo {

VkStructureType  sType;

const void*  pNext;

VkBufferCreateFlags  flags;

VkDeviceSize  size;

VkBufferUsageFlags  usage;

VkSharingMode  sharingMode;

uint32_t  queueFamilyIndexCount;

const uint32_t* pQueueFamilyIndices;

} VkBufferCreateInfo;sType應當被設定為VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,pNext應被設定為nullptr—除非你想要使用拓展。flags告訴Vulkan有關Buffer的屬性資訊。在目前的Vulkan版本中,隻能設定為sparse buffes相關的值,我們将在本章稍後部分講解。暫時,flags被設定為0。

size設定了buffer的大小,以bytes為機關。usage告訴Vulkan你如何使用buffer,它隻能被設定為VkBufferUsageFlagBits這個枚舉類型的某一個值。在某些架構中,buffer的使用方式會影響到被建立的過程。本章中用到的設定值有下面幾個:

l VK_BUFFER_USAGE_TRANSFER_SRC_BIT 、VK_BUFFER_USAGE_TRANSFER_DST_BIT 表示在轉移commands過程中,可以被用來做源位址或者目的地。轉移operatin會把資料從源位址copy到目标位址。第四章将會講解。

l VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT、VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT表示buffer可被用來存儲uniform或者storage texel。Texel buffer是存放像素的格式化的數組,可以被用作源位址或者目标位址,被運作在GPU上的shader讀寫。Texel Buffer将在第六章講解。

l VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT 、 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT表示可以存儲uniform或者storage buffer。和texel buffers相反,正常的uniform和storage buffers并沒有格式,可用來存儲任意的資料。我們在第六章“Shaders and Pipelines“中講解。

l VK_BUFFER_USAGE_INDEX_BUFFER_BIT 、 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT可以用來存放索引或者頂點資料,被繪制commands使用。在第八章”繪制“中,我們講解繪制指令,包含索引化的繪制指令。

l VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT表示可以存儲間接派發與繪制指令的參數,這些commands從buffers中直接擷取參數,而不是從應用程式。在第六章和第八章會講解。

VkBufferCreateInfo的sharingMode域,表示buffer将在GPU支援的多個command queues中如何被使用。因為Vulkan并行的執行多個operation,一些Vulkan實作需要知道buffer是被一個還是被多個command使用。設定sharingMode為VK_SHARING_MODE_EXCLUSIVE時,表明buffer隻會被一個queue使用,設定為VK_SHARING_MODE_CONCURRENT時表示你計劃在多個queue中同時使用這個buffer。使用VK_SHARING_MODE_CONCURRENT可能會導緻在一些系統上低效率,是以,除非你的确需要才設定為這個值。

如果你真的設定為VK_SHARING_MODE_CONCURRENT,你需要告訴Vulkan哪些queue将使用這個buffer。這通過設定VkBufferCreateInfo,的pQueueFamilyIndices域來完成,這是一個指向queue families數組的指針。queueFamilyIndexCount是數組的長度,是将使用這個buffer的queue families的個數。當sharingMode被設定為VK_SHARING_MODE_EXCLUSIVE時,queueFamilyCount、pQueueFamilies都會被忽略。

Listing 2.3示例了如何建立一個1MB大小的buffer對象,可讀可寫,還有每次隻被一個queue family使用。

Listing 2.3: Creating a Buffer Object

static const VkBufferCreateInfo bufferCreateInfo =

{

VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr,

0,

1024 * 1024,

VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,

VK_SHARING_MODE_EXCLUSIVE,

0, nullptr

};VkBuffer buffer = VK_NULL_HANDLE; 

vkCreateBuffer(device, &bufferCreateInfo, &buffer);

在Listing 2.3中的代碼被運作後,一個新的VkBuffer的handle被建立,并且被指派到buffer變量。這個buffer并不能被使用,因為,他首先需要被存放到記憶體,這個操作将在本章的”裝置記憶體管理“小節中講到。

格式 和 Support?

Buffer是相對簡單的資源類型,存放的資料沒有格式的概念,images和buffer views包含有他們内容的相關資訊。部分資訊描述了資源中資料的格式。一些格式對特定的管線中使用它們有特殊的要求或者限制。例如,一個格式可讀但是不可寫,這在壓縮格式中很常見。

為了知道對各種格式的屬性和supoort級别,你可以調用vkGetPhysicalDeviceFormatProperties(),原型如下:

void vkGetPhysicalDeviceFormatProperties (

VkPhysicalDevice  physicalDevice,

VkFormat  format,

VkFormatProperties*  pFormatProperties);

因為對實體裝置而非邏輯裝置特定格式的支援,實體裝置的handle是被physicalDevice.指定的。如果應用程式需要完全支援某些格式,你可以在建立邏輯裝置之前做檢查,或者在應用程式啟動時拒絕特定的實體裝置。如果裝置識别格式,它将把支援級别寫到instance的VkFormatProperties類型的域pFormatProperties.。VkFormatProperties的定義如下:

typedef struct VkFormatProperties {

VkFormatFeatureFlags  linearTilingFeatures;

VkFormatFeatureFlags  optimalTilingFeatures;

VkFormatFeatureFlags  bufferFeatures;

} VkFormatProperties;VkFormatProperties的三個域都是位域,可選值由VkFormatFeatureFlagBits這個枚舉中的某些值構成。一幅圖像可以是單列或者是塊狀模式:線性的,就是在記憶體中連續的排列,先按行,再按照列排放;或者最優,圖像資料以最優方案被排放,可以最高效率的利用顯示卡記憶體子系統。linearTilingFeatures域表示對一種格式線性鋪排的支援級别,optimalTilingFeatures表示對圖像優化鋪排方式的支援級别,bufferFeatures表示對buffer使用的支援級别。

可選的bit值定義如下:

l VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT 這種格式被 shader采樣的隻讀圖像使用

l VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT 過濾模式,包含線性過濾,這種格式用于被采用的image

l VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT: 這種格式被shader可讀寫的images使用

l VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT: 這種格式被 支援shader的atomic操作的可讀寫images使用。

l VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT: 這種格式被shader隻讀的texel buffer使用

l VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT:此格式 被shader讀寫的texel buffer使用

l VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT:此格式被 支援shader原子操作的texel buffers使用

l VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT:此格式被 管線的頂點組裝階段用作源位址的頂點資料使用

l VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT:此格式被管線的顔色混合階段用作顔色附件使用

l VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT:當blending被啟用時,有此格式的images可被用作顔色附件

l VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT:此格式可被深度、擋闆,或者深度-擋闆 附件使用

l VK_FORMAT_FEATURE_BLIT_SRC_BIT: 此格式被用作image拷貝操作的源資料使用

l VK_FORMAT_FEATURE_BLIT_DST_BIT: 此格式被用作image拷貝操作的目的資料使用

許多格式是幾種狀态位的組合。實際上,許多格式被強制支援。在Vulkan技術規範文檔中,有一個完整的“必須支援“格式清單。如果一種格式在此清單中,那麼它不需要被強制去測試是否支援。然而,完了完整性,各種Vulkan實作被期待會準确的向Vulkan委員會彙報對各種格式,甚至是必須支援格式的相容性。

vkGetPhysicalDeviceFormatProperties()函數會傳回一個粗糙的結果集,告訴我們一個格式是否可被用在特定的場景。對images來說,一個特定格式和對images不同支援級别之間的互相影響會複雜多了。是以,當用于images時,為了更多的擷取對格式的支援資訊,你可以調用vkGetPhysicalDeviceImageFormatProperties(),原型如下:

VkResult vkGetPhysicalDeviceImageFormatProperties (

VkPhysicalDevice  physicalDevice,

VkFormat  format,

VkImageType  type,

VkImageTiling  tiling,

VkImageUsageFlags  usage,

VkImageCreateFlags  flags,

VkImageFormatProperties*  pImageFormatProperties);

與vkGetPhysicalDeviceFormatProperties(),類似,vkGetPhysicalDeviceImageFormatProperties()接受一個VkPhysicalDevice handle作為第一個參數,回報實體裝置而非邏輯裝置對某個格式的支援結果。你查詢的這個格式通過format參數傳遞。

你想詢問的image的類型通過type指定。它應當是images 類型中的某一個:VK_IMAGE_TYPE_1D,VK_IMAGE_TYPE_2D,VK_IMAGE_TYPE_3D。不同的image類型也許有不同的限制條件和增強措施。Image的Tiling模式是通過tiling參數指定的,值為VK_IMAGE_TILING_LINEAR或者VK_IMAGE_TILING_OPTIMAL,表示線性或者最優鋪排。

Image的類型是通過usage參數指定的。這個位域表明image就如何被使用。如何使用images将在本章稍後講到。flags參數應當被設定為和建立image時同樣。

如果這個格式被識别并且被Vulkan的實作所支援,那麼支援級别将會寫入到一個VkImageFormatProperties類型的資料結構pImageFormatProperties. VkImageFormatProperties的定義如下:

typedef struct VkImageFormatProperties {

VkExtent3D maxExtent;

uint32_t  maxMipLevels;

uint32_t  maxArrayLayers;

VkSampleCountFlags  sampleCounts;

VkDeviceSize  maxResourceSize;

} VkImageFormatProperties;VkImageFormatProperties的成員extent報告了某個格式的image在建立時最大尺寸的大小。例如,每個像素占位(bit)更少的格式比占位更多的格式,可以建立更大的image。Extent是VkExtent3D類型的資料,定義如下:

typedef struct VkExtent3D {

uint32_t  width;

uint32_t  height;

uint32_t  depth;

} VkExtent3D;

maxMipLevels域,報告了一個 指定格式的image可以支援的最大mipmap個數。多數情況下,maxMipLevels要麼報告log2 (max (extent.x, extent.y, extent.z)),要麼 1 表示不支援mipmap。

maxArrayLayers域報告了image支援的array layers最大數量。再次強調,如果arrays被支援,或不支援時為1,這幾可能會是一個非常大的數字。

如果 image格式支援多重采樣,那麼支援的采樣數通過sampleCounts獲得,這是yige位字段,每一位都表示支援的采樣數量。如果n被設定,那麼支援2n 采樣的images就能夠被這種格式支援。如果格式完全支援,這個位字段至少有一個位是被設定過的。幾乎不可能看到支援多重采樣但不支援單采樣的格式。

最後,maxResourceSize域,指定了這個格式的資源,以byte為機關最大的大小。此域不應當和maxExtent混淆了。maxExtent表示了支援的每一個次元的最大值。比如,某個Vulkan實作表示可以支援16,384 × 16,384 pixels × 2,048 layers的image,每個像素128 bits。那麼,以每個次元的最大值來穿件圖像,将會産生8TB的資料。該Vulkan實作幾乎不會真的實作支援建立8TB的圖像。然而,它可能支援建立n 8 × 8 × 2,048 array or a 16,384 × 16,284 nonarray 圖像,兩者都可以放到合适的記憶體塊中。

Images

Images比buffers更加複雜,因為他們是多元的;有獨特的布局和格式資訊;即可被用作過濾、混合、深度或者stencil測試等操作的源位址 或者是目的位址。可以用vkCreateImage()函數建立images,原型如下:

VkResult vkCreateImage (

VkDevice  device,

const VkImageCreateInfo*  pCreateInfo,

const VkAllocationCallbacks* pAllocator,

VkImage* pImage);

被用來建立image的的裝置,通過device參數被傳入。Image相關的資訊通過一個資料結構pCreateInfo被傳入。它是一個VkImageCreateInfo類型 資料的指針,定義如下:

typedef struct VkImageCreateInfo {

VkStructureType  sType;

const void*  pNext;

VkImageCreateFlags  flags;

VkImageType  imageType;

VkFormat  format;

VkExtent3D  extent;

uint32_t  mipLevels;

uint32_t  arrayLayers;

VkSampleCountFlagBits  samples;

VkImageTiling  tiling;

VkImageUsageFlags  usage;

VkSharingMode  sharingMode;

uint32_t  queueFamilyIndexCount;

const uint32_t*  pQueueFamilyIndices;

VkImageLayout  initialLayout;

} VkImageCreateInfo;

你可以看到,這是一個比VkBufferCreateInfo顯著複雜的資料結構。常見的域,sType、 pNext,在最前面,與其他的多數Vulkan内部資料結構類似。sType域應當被設定為VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO。flags域包含描述image的屬性資訊。可以從VkImageCreateFlagBits這個枚舉中選擇幾個值來構造。前面三個-- VK_IMAGE_CREATE_SPARSE_BINDING_BIT, VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT, and VK_IMAGE_CREATE_SPARSE_ALIASED_BIT –是用來控制稀疏圖像的,在本章稍後講解。

如果被設定為VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT,那麼你可以為image建立具有不同格式view。Image views(image視圖)基本上是一種特殊的圖像,它可以和父圖像共享資料和布局,但是可以表現出不同的格式。這就允許了image的資料在同時被不同的方式解讀。使用圖像視圖,就可以使用一份資料建立多個iamge。本章稍後講解。如果被設定為VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT,那麼你可以建立立方紋理視圖。立方紋理視圖于本章稍後講解。

imageType 域指定了你想建立的圖像的類型。圖像類型基本上就是圖像的次元,可選值有VK_IMAGE_TYPE_1D, VK_IMAGE_TYPE_2D, VK_IMAGE_TYPE_3D,分别表示1D,2D,3D。

圖像也有格式,它描述了像素資料是如何在記憶體在存放的,并且是如何被Vulkan讀取的。圖像的格式是通過formats指定的,而且必須是由VkFormat這個枚舉的值組成的。Vulkan支援很大數量的格式—在這裡無法列出。我們在本書中使用某些作為例子并加以講解。剩下的格式,請參考Vulkan文檔。

圖像的extent是指以像素為機關的大小。通過extent域指定,它是VkExtent3D類型的資料,有width, height, depth三個成員。他們應當被設定為目标圖像的寬度,高度和深度。對于1D圖像,高度是1,對于1D、2D圖像,depth需被設定為1。相較于把下一次元當作數組的大小,Vulkan顯式的指定 數組大小,通過arrayLayers.指定。

能夠建立的圖像的大小依賴于每個GPU裝置。想要擷取這個最大數值,可調用vkGetPhysicalDeviceFeatures()并且檢查内嵌的VkPhysicalDeviceLimits結構的 maxImageDimension1D, maxImageDimension2D, 和 maxImageDimension3D。maxImageDimension1D包含一維圖像的最大寬度,maxImageDimension2D、maxImageDimension3D都包含最後一維的最大值。同樣的,maxImageArrayLayers包含了image可擁有的層數的最大值。

如果這是一張立方紋理,那麼最後一位的最大值就被存儲在maxImageDimensionCube。maxImageDimension1D, maxImageDimension2D, 和 maxImageDimensionCube 都被保證不小于4096像素,且maxImageDimensionCube和maxImageArrayLayers被保證不小于256。如果想要建立的圖像比這些維數的最大值小,那麼就無需檢查硬體的特征。進一步來講,Vulkan實作一般都會支援遠高于最低标準的規格。是以,我們可以合理的假定可以建立更大的圖像,而不是為了适配低端裝置做容錯處理。

mipLevels.指定了mipmap的層數。Mipmapping是為了提高降采樣的品質而預先提供的一組被過濾過的圖檔。這些圖檔以金字塔的形式組成了mipmap的各個層級。

Vulkan程式設計指南翻譯 第二章 第二節 資源

在一個mipmapped 貼圖中,基礎級别是最小号碼的級别(通常是0),并且擁有貼圖的原裝尺寸。後繼的級别依次有上一層的一半大小,直到某個次元的尺寸變為一個像素。從mipmaped的貼圖進行采用将在第六章講解。

同樣的,samples指定了采樣的次數。這個域與其他的不大相似。它必須是VkSampleCountFlagBits這個枚舉中的某個值,是一個bit定義、用在位域的變量。然而,在現在的Vulkan中,隻有2的幂采樣數才能被使用,意味着它們隻用1表示含義,是以,按位的枚舉值就可以工作了。

餘下的幾個域描述了圖像就會被如何使用。首先是tiling模式,通過tiling域指定。這是一個VkImageTiling枚舉類型的變量,隻有VK_IMAGE_TILING_LINEAR、 VK_IMAGE_TILING_OPTIMAL這兩個選項。Linear tiling表示圖像資料從左到右,從上到下被存放,如果你映射到底層記憶體或者通過CPU寫入,他将形成線性的圖像。同時,優化tiling是不透明的表示方式,由Vulkan在記憶體中存放,使GPU的記憶體子系統更高效的通路。這是你多數時候的選項,除非你打算用CPU來操作資料。對于絕大多數操作,優化tiling會比線性tiling表現的顯著高效,而且線性tiling也不被一些操作和格式所支援,這取決于Vulkan的具體實作者。

usage 也是位域變量,描述了圖像在哪兒被使用。這和VkBufferCreateInfo的usage類似。這裡的usage由VkImageUsageFlags枚舉值形成,如下:

l VK_IMAGE_USAGE_TRANSFER_SRC_BIT 、 VK_IMAGE_USAGE_TRANSFER_DST_BIT表示圖像圖像操作的源位址和目标位址。圖像轉移指令将在第四章講解。

l VK_IMAGE_USAGE_SAMPLED_BIT 表示圖像可以被shader采樣

l VK_IMAGE_USAGE_STORAGE_BIT表示圖像可以被用作通用存儲,包括shader的寫入

l VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT表示圖像可以綁定一個顔色附件并且用繪制操作卷入。Framebuffers和它們的附件在第七章繪制管線中講解。

l VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT表示圖像可以綁定一個深度或者stencil附件,且用作深度或者stencil測試。深度或者stencil操作在第十章“像素處理“中講解。

l VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT表示圖像可以被用作臨時附件,是一種特殊的圖像,被用于存儲繪制操作的中間結果。臨時附件在第十三章”多遍渲染“中講解。

l VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT表示圖像可被用作渲染過程中的特殊輸入。輸入圖像和正常菜呀或存儲的圖像不一樣的點在于fragment shader可以讀取他們的像素點。輸入輸入附件在第十三章。

sharingMode 與本章早一些提到的VkBufferCreateInfo結構的同名成員,在功能上是相同的。若被設定為VK_SHARING_MODE_EXCLUSIVE,這個圖像将在某個時刻隻能被一個隊列使用。若設定為VK_SHARING_MODE_CONCURRENT,,那麼圖像可以同時被多個queue通路到。同樣,當sharingMode 被設定為VK_SHARING_MODE_CONCURRENT. 時,queueFamilyIndexCount和pQueueFamilyIndices與上面小節的功能描述相同。

最後,圖像有布局(layout),在某種程度上指定了在任意時刻它将會被如何使用。initialLayout域決定了圖像以哪種布局被建立。VkImageLayout這個枚舉類型定義了可用的布局方式,他們如下:

l VK_IMAGE_LAYOUT_UNDEFINED:

l VK_IMAGE_LAYOUT_GENERAL:

l VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:

l VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:

l VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:

l VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:

l VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:

l VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:

l VK_IMAGE_LAYOUT_PREINITIALIZED:

l VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:

圖像可從一個布局轉移到另外一個,我們将會在相關章節講到不同的布局。然而,圖像初始建立時,隻能是VK_IMAGE_LAYOUT_UNDEFINED或者VK_IMAGE_LAYOUT_PREINITIALIZED布局。當你在記憶體中有資料并且迅速綁定到圖像資源時,才使用VK_IMAGE_LAYOUT_PREINITIALIZED。當你在使用前,計劃把資源轉移到另外一個布局,應當使用VK_IMAGE_LAYOUT_UNDEFINED。任何時候,當圖像被移出VK_IMAGE_LAYOUT_UNDEFINED layout時,幾乎沒有性能消耗。

改變圖像布局的機制也被稱為”管線壁壘“,或”壁壘“。一個壁壘,不僅僅是改變資源布局的途徑,也可以用來同步Vulkan管線不同階段,甚至在一個GPU裝置上同時運作的隊列,對該資源的通路。由此,管線壁壘相當的複雜,正确的使用它并不簡單。管線壁壘在第四章深度講解。

Listing 2.4 展示了一個簡單的圖像資源建立的例子

Listing 2.4: Creating an Image Object

VkImage image = VK_NULL_HANDLE;

VkResult result = VK_SUCCESS;

static const VkImageCreateInfo imageCreateInfo =

{

VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,  // sType

nullptr, // pNext

0,  // flags

VK_IMAGE_TYPE_2D, // imageType

VK_FORMAT_R8G8B8A8_UNORM,  // format

{ 1024, 1024, 1 },  // extent

10,  // mipLevels

1,  // arrayLayers

VK_SAMPLE_COUNT_1_BIT, // samples

VK_IMAGE_TILING_OPTIMAL, // tiling

VK_IMAGE_USAGE_SAMPLED_BIT,  // usage

VK_SHARING_MODE_EXCLUSIVE,  // sharingMode

0,  // queueFamilyIndexCount

nullptr,  // pQueueFamilyIndices

VK_IMAGE_LAYOUT_UNDEFINED  // initialLayout

};

result = vkCreateImage(device, &imageCreateInfo, nullptr, &image);

在Listing 2.4中建立的圖像是一個1,024 × 1,024 2D圖像,單采樣,VK_FORMAT_R8G8B8A8_UNORM格式,最優tiling。代碼以未定義布局建立了它,這表示我們可以把它轉移到另外一個地方兵器用資料填充它。這個圖像将會被作為貼圖使用被shader通路,是以,我們設定usage為VK_IMAGE_USAGE_SAMPLED_BIT。在我們簡單的應用程式中,我們隻是用單一隊列,是以,我們設定共享模式為exclusive.

線性圖像

如之前章節讨論過的,各種資源都有兩種tiling模式:VK_IMAGE_TILING_LINEAR and VK_IMAGE_TILING_OPTIMAL。VK_IMAGE_TILING_OPTIMAL是一種不透明,實作方式各異的布局,是為了提高裝置記憶體子系統對圖像的讀寫性能。然而,VK_IMAGE_TILING_LINEAR是一種不可見(transparent)的資料布局方式,是為了足夠的直覺,在圖像内部,像素以從左到右,從上倒下的方式布局,幾乎不可能把資料映射到資源并讓CPU直接的讀寫。

如果想讓CPU可以通路潛在的圖像資料,除了圖像的寬度,高度,深度,像素格式,還有幾個其他的資訊是必需的:圖像的row pitch--; array pitch – 不同array layer之間的距離; depth pitch – 深度切片間的距離。當然,array pitch 和 depth pitch分别應對于array 或 3D 圖像,row pitch隻可用于2D和3D圖像。

一個圖像通常是由幾個子資源組成的。一些格式有多于一個的aspect,是類似于深度圖像的深度或者stencil 成分的一種成分。一個image下不同的子資源的布局可能是不同的,是以有不同的布局資訊。這個資訊可調用vkGetImageSubresourceLayout()來查詢,原型如下:

void vkGetImageSubresourceLayout (

VkDevice device,

VkImage image,

const VkImageSubresource* pSubresource,

VkSubresourceLayout* pLayout);

被查詢圖像所在的裝置通過device參數傳遞過去,查詢的圖像通過image參數傳遞。子資源的資訊通過一個VkImageSubresource類型的指針pSubresource,傳遞回來,定義如下:

typedef struct VkImageSubresource {

VkImageAspectFlags  aspectMask;

uint32_t  mipLevel;

uint32_t  arrayLayer;

} VkImageSubresource;