Vulkan没有默认帧缓冲区的概念,在送显上屏之前,需要一个基础结构来持有一些缓冲区。Vulkan引入了交换链的概念。
交换链本质上就是一个(用于送显上屏)图像的等待队列。应用程序获取一个图像,绘制内容,然后返回到队列。队列如何工作,队列中图像如何送显上屏 取决于交换链的配置参数。
交换链的作用就是同步图像的上屏和屏幕的刷新。
0 Surface的校验
验证GPU是否支持surface的显示,vulkan标准内没有窗体surface的概念,外在的因素不可控所以要校验,
// Section1: check
VkBool32 vk_queue_family_supports_present = false;
auto hr = vkGetPhysicalDeviceSurfaceSupportKHR(device.gpuDevice_, device.queueFamilyIndex_, device.surface_, &vk_queue_family_supports_present);
if (hr != VK_SUCCESS || !vk_queue_family_supports_present) {
LOGE("surface not founded...");
exit(1);
}
这个接口第二个参数是queue的索引,多个队列需要循环遍历,手机上一般1个队列有效。
1 Surface Format相关
同样手段,先取长度 再填充vector。
// Query the list of supported surface format and choose one we like
uint32_t formatCount = 0;
hr = vkGetPhysicalDeviceSurfaceFormatsKHR(device.gpuDevice_, device.surface_,
&formatCount, nullptr);
if (hr != VK_SUCCESS || formatCount == 0) {
LOGE("could not get number of physical device formats for device");
exit(1);
}
std::vector<VkSurfaceFormatKHR> formats; formats.resize(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(device.gpuDevice_, device.surface_,
&formatCount, formats);
LOGI("Got %d formats", formatCount);
// 至少必须有RGBA8888啊,
uint32_t chosenFormat;
for (chosenFormat = 0; chosenFormat < formatCount; chosenFormat++) {
if (formats[chosenFormat].format == VK_FORMAT_R8G8B8A8_UNORM) break;
}
assert(chosenFormat < formatCount);
surfaceFormat结构里有两个字段,pixelFormat和colorSpace:
- 格式主要sRGB最常见的,SCRGB是FP16表示每个通道,R16G16B16A16。RGB也有两种:最普通的UNORM,和非线性的,后者非常少见。
- 颜色空间,分线性和非线性的。
关于这两个概念补充一段:
Vulkan 本身与色彩空间无关。不过,在数字电信号转换为光信号之前的某个阶段,色彩空间必须明确。这就是在交换链创建过程中需要指定色彩空间的原因。
- imageFormat指定图像格式是什么(与vkCreateImage()中的作用相同)。
- imageColorSpace则表示在图像呈现时,交换链 / 显示器对这些数值的解释方式。
所以,如果使用UNORM,这意味着色彩空间未指定,数据只是普通的原始数据位。或者更确切地说,这意味着由你来负责色彩空间(前提是图像确实存储颜色信息,而不是完全其他类型的数据)。
如果你将VK_COLOR_SPACE_SRGB_NONLINEAR_KHR与_UNORM搭配使用,这意味着交换链获取你的数据位,并在呈现时假定这些数据已经是sRGB 格式。
如果使用的是_SRGB,那么对于交换链本身来说没有区别,但实际情况是创建的VkImages是_SRGB格式,这意味着当你使用它们时,颜色会为你进行线性化处理(与创建非交换链的VkImage时的情况相同)。
扩展一下,谈谈色域。显示器的能力,依赖于硬件是否支持,最广泛和古老的格式是sRGB,P3(广色域),BT2020,HDR10,杜比,后面几种在HDR渲染中经常遇到,目前旗舰手机都支持hdr,iphone12是第一款集采集、处理、显示的终端设备。
要正常渲染,至少得有一种格式,R8G8B8A8_UNORM,否则就退出。P40Pro手机查询到支持5种格式,
(VkSurfaceFormatKHR) (format = VK_FORMAT_R8G8B8A8_UNORM, colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
(VkSurfaceFormatKHR) (format = VK_FORMAT_R8G8B8A8_SRGB, colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
(VkSurfaceFormatKHR) (format = VK_FORMAT_R5G6B5_UNORM_PACK16, colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
(VkSurfaceFormatKHR) (format = VK_FORMAT_R16G16B16A16_SFLOAT, colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
(VkSurfaceFormatKHR) (format = VK_FORMAT_A2B10G10R10_UNORM_PACK32, colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
几种格式介绍:
- 常规的至少要有RGBA8888,
- 3th:565是压缩格式,
- 5th:支持HDR显示需要的格式至少1010102,
- 4th:要到HDR-vivid,则得用格式12121212,
3 SurfaceCapabilities
VkSurfaceCapabilitiesKHR surfaceCapabilities;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device.gpuDevice_, device.surface_,&surfaceCapabilities);
主要获取交换链的长度,以及渲染目标的尺寸限制。
3.1 窗口尺寸
相关的三个变量,单位都是像素,跟渲染
VkExtent2D currentExtent; 当前窗口的尺寸,可能无效,
VkExtent2D minImageExtent; 最小尺寸
VkExtent2D maxImageExtent; 最大尺寸
// SectionX
VkExtent2D swap_chain_extent;