选择交换链图像的格式
译者注:示例代码点击此处
格式定义颜色分量的数量,每个组件的位数以及使用的数据类型。 在交换链创建期间,我们必须指定是否要使用带或不带alpha分量的红色,绿色和蓝色通道,是否应使用无符号整数或浮点数据类型对颜色值进行编码,以及它们的精度是什么。 我们还必须选择是否使用线性或非线性颜色空间对颜色值进行编码。 但与其他交换链参数一样,我们只能使用呈现表面支持的值。
做好准备
在这节内容中,我们使用了几个看似相同的术语,但实际上它们指定了不同的参数:
·图像格式用于描述图像像素的分量,精度和数据类型。它对应VkFormat类型的变量。
·颜色空间决定了硬件解释颜色分量值的方式,无论他们是使用线性函数还是非线性函数进行编码或解码。颜色空间对应于VkColorSpaceKHR类型的变量。
·表面格式是一对儿图像格式和颜色空间,由VkSurfaceFormatKHR类型的变量表示。
怎么做...
1.获取vkEnumeratePhysicalDevices()函数返回的物理设备句柄。将其储存在名为physical_device的VkPhysicalDevice类型变量中。
2.获取创建的呈现表面并将其句柄储存在名为presentation_surface的VkSurfaceFormatKHR类型变量中。
3.选择所需的图像格式和颜色空间,并将他们分配给名为desired_surface_format的VkSurfaceFormatKHR类型的成员变量中。
4.创建名为formats_count的uint32_t类型变量。
5.调用vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, presentation_surface, &formats_count, nullptr),第一个参数提供物理设备句柄,第二个参数为呈现表面的句柄,第三个参数指向formats_count变量,最后一个参数为nullptr。
6.如果函数调用成功,则formats_count变量将包含所有支持的格式-颜色空间对的数量。
7.创建一个名为surface_formats的std::vector<VkSurfaceFormatKHR>类型变量,尺寸至少能够保存formats_count数量的元素。
8.调用vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device,presentation_surface, &formats_count, &surface_formats[0] )。为前三个参数提供相同的参数。最后一个参数中提供指向surface_formats向量的第一个元素的指针。
9.如果调用成功,所有可用的图像格式-颜色空间对将储存在surface_formats变量中。
10.创建名为image_format的VkFormat类型变量和名为image_color_space的VkColorSpaceKHR类型的变量。我们在其中储存稍后再交换链创建期间使用的格式和颜色空间的选定值。
11.检查surface_formats向量中的元素数。如果它只包含一个值为VK_FORMAT_UNDEFINED的元素,则意味着我们可以选择我们想要的任何表面格式,将desired_surface_format变量的成员分配给image_format和image_color_space变量。
12.如果surface_formats向量包含该更多的元素,则迭代向量的每个元素,并将format和colorSpace成员与desired_surface_format变量的相同成员进行对比。如果找到两个成员相同的元素,则意味着支持所需的表面格式,我们可以将其用于交换链创建,将desired_surface_format变量的成员分配给image_format和image_color_space变量。
13.如果我们没找到匹配的项,则迭代surface_formats向量的所有元素,检查其它的任何元素的格式是否与所选的surface_format.format的值相同,如果是存在这样的元素,请将desired_surface_format.format值指定给image_format变量,但从surface_formats的当前查看元素中获取相应的颜色空间,并将其指定给image_color_space变量。
14.如果surface_formats变量不包含所选图像格式的任何元素,请获取向量的第一个元素,并将其format和colorSpace成员分配给image_format和image_color_space变量。
这个怎么运作...
为了获得所有支持的表面格式的列表,我们需要对vkGetPhysicalDeviceSurfaceFormatsKHR()函数进行双重调用。首先,我们获得支持格式-颜色空间对的数目:
uint32_t formats_count = 0;
VkResult result = VK_SUCCESS;
result = vkGetPhysicalDeviceSurfaceFormatsKHR( physical_device, presentation_surface, &formats_count, nullptr ); if( (VK_SUCCESS != result) || (0 == formats_count) ) {
std::cout << "Could not get the number of supported surface formats." << std::endl;
return false;
}
接下来,可以为实际值准备储存容器,并进行第二次调用以获取它们。
std::vector<VkSurfaceFormatKHR> surface_formats( formats_count );
result = vkGetPhysicalDeviceSurfaceFormatsKHR( physical_device, presentation_surface, &formats_count, surface_formats.data() );
if( (VK_SUCCESS != result) || (0 == formats_count) ) {
std::cout << "Could not enumerate supported surface formats." << std::endl;
return false;
}
在此之后,可以选择一个支持的表面格式,这是最好的匹配我们的需求。如果只返回一个表面格式,并且它的值为VK_FORMAT_UNDEFINED,则意味着对支持的格式-颜色空间对没有限制。在这种情况下,可以选择我们想要的任何表面格式,并在创建交换链中使用它。
if( (1 == surface_formats.size()) && (VK_FORMAT_UNDEFINED == surface_formats[0].format) ) {
image_format = desired_surface_format.format;
image_color_space = desired_surface_format.colorSpace;
return true;
}
如果有更多的元素,那么我们需要其中的一个。首先,我们检查所选择的表面格式是否被“完全”支持——所选择的图像格式和颜色空间都是可用的:
for( auto & surface_format : surface_formats ) {
if( (desired_surface_format.format == surface_format.format) && (desired_surface_format.colorSpace == surface_format.colorSpace) ) {
image_format = desired_surface_format.format;
image_color_space = desired_surface_format.colorSpace;
return true;
}
}
如果找不到匹配项,则寻找具有相同图像格式但其它颜色空间的成员。我们不能采用任何支持的格式和任何支持的颜色空间——我们必须采用与给定格式相对应的颜色空间:
for( auto & surface_format : surface_formats ) {
if( (desired_surface_format.format == surface_format.format) ) {
image_format = desired_surface_format.format;
image_color_space = surface_format.colorSpace;
std::cout << "Desired combination of format and colorspace is not supported. Selecting other colorspace." << std::endl;
return true;
}
}
最后,如果不支持我们想要支持的格式,只需要使用第一个可用的图像格式-颜色空间对:
image_format = surface_formats[0].format;
image_color_space = surface_formats[0].colorSpace;
std::cout << "Desired format is not supported. Selecting available format - colorspace combination." << std::endl;
return true;