Vulkan Cookbook 第二章 5 选择期望的呈现模式

选择期望的呈现模式

译者注:示例代码点击此处

在屏幕上显示图像的能力是Vulkan交换链的最重要特征之一 - 事实上,它是交换链的设计目的。 在OpenGL中,当我们完成渲染到后台缓冲区时,只是用前缓冲区切换它,渲染的图像显示在屏幕上。 我们只能确定是否要显示图像以及消隐间隔(如果我们想要启用v-sync)。
在Vulkan中,不仅限于我们可以渲染的一个图像(后缓冲区)。 并且,我们可以选择在屏幕上显示图像的其中一种方式,而不是两个(启用或禁用v-sync)。 这称为呈现模式,我们需要在交换链创建期间指定它。

怎么做...

1.使用vkEnumeratePhysicalDevices()函数枚举的物理设备句柄。储存在名为physical_deviceVkPhysicalDevice类型变量中。
2.获取创建的呈现表面并将其句柄处存在名为presentation_surfaceVkSurfaceKHR类型变量中。
3.创建名为desired_present_modeVkPresentModeKHR类型的变量。在此变量中储存所需的呈现模式。
4.准备名为present_modes_countuint32_t类型的变量。
5.调用vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, presentation_surface, &present_modes_count, nullptr)。提供物理设备句柄和呈现表面句柄作为前两个参数,第三个参数指向present_modes_count变量。
6.如果调用成功,则present_modes_count变量将包含支持的呈现模式的数量。
7.创建一个名为present_modestypestd::vector<VkPresentModeKHR>类型变量,将向量调整为之少可以包含present_modes_count个元素。
8.再次调用vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, presentation_surface, &present_modes_count,  &present_modes[0])。 但这次,在最后一个参数中,提供只想present_modes向量的第一个元素的指针。
9.如果函数返回VK_SUCCESS值,则present_modes变量中储存了呈现模式。
10.迭代present_modes向量的所有元素,检查其中一个元素是否等于储存在desired_present_mode变量中的所需呈现模式。
11.如果不支持所需的呈现模式,选择FIFO呈现模式-VK_PRESENT_MODE_FIFO_KHR--他始终应该被支持。

这个怎么运作...

呈现模式定义了图像在屏幕上的显示方式。目前Vulkan API中定义了四种模式。最简单是IMMEDIATE模式。这里,当呈现图像时,他立即替换正在显示的图像。没有等待,没有队列,也没有其他参数。所以屏幕画面有可能观察到撕裂现象。

每个Vulkan API实现必须支持的强制表示模式是FIFO模式。 这里,当呈现图像时,它被添加到先进先出队列(该队列的长度等于交换链中的图像的数量减去1,n-1)。 在此队列中,图像与消隐期(v-sync)同步显示在屏幕上,始终与添加到队列的顺序相同。 在此模式下没有撕裂,因为启用了v-sync。 此模式类似于OpenGL的缓冲区交换,交换间隔设置为1。

提示:必须始终支持FIFO呈现模式。

还有一种称为FIFO RELAXED的模式,它在FIFO略有修改。 两者之间的区别在于,在RELAXED模式下,只有当图像以足够快的速度显示,比刷新率更快时,图像才会与消隐周期同步显示在屏幕上。 如果应用程序显示图像,并且从上次显示开始经过的时间大于两个消隐期间之间的刷新时间(FIFO队列为空),则立即显示图像。 因此,如果我们足够快,没有屏幕撕裂,但如果我们绘制的速度比显示器的刷新速度慢,则屏幕撕裂将可见。 此行为类似于OpenGL的EXT_swap_control_tear扩展中指定的行为:


最后一种呈现模式称为邮箱模式。 它可以被视为三重缓冲。 这里也有一个队列,但它只包含一个元素。 在此队列中等待的图像与消隐期同步显示(启用了v-sync)。 但是当应用程序显示图像时,新图像将替换队列中等待的图像。 因此,呈现引擎始终显示最新的可用图像。 而且没有屏幕撕裂:

要选择所需的呈现模式,我们需要检查当前平台上可用的模式。 首先,我们需要获取所有支持的呈现模式的数量。 这是通过调用vkGetPhysicalDeviceSurfacePresentModesKHR()函数并将最后一个参数设置为nullptr来完成的:

uint32_t present_modes_count = 0; 
VkResult result = VK_SUCCESS;

result = vkGetPhysicalDeviceSurfacePresentModesKHR( physical_device, presentation_surface, &present_modes_count, nullptr); 
if( (VK_SUCCESS != result) || (0 == present_modes_count) ) {
  std::cout << "Could not get the number of supported present modes." << std::endl; 
  return false;
}

接下来,我们可以为所有支持的模式准备存储容器,并再次调用相同的函数,但这次最后一个参数指向存储容器:

std::vector<VkPresentModeKHR> present_modes( present_modes_count );
result = vkGetPhysicalDeviceSurfacePresentModesKHR( physical_device, presentation_surface, &present_modes_count, present_modes.data() );
if( (VK_SUCCESS != result) || (0 == present_modes_count) ) {
  std::cout << "Could not enumerate present modes." << std::endl; 
  return false;
}

现在我们知道可用的呈现模式,我们可以检查所选模式是否可用。 如果不是我们可以选择另一种模式,或者我们只用必需支持的FIFO模式:

for( auto & current_present_mode : present_modes ) {
  if( current_present_mode == desired_present_mode ) { 
    present_mode = desired_present_mode;
    return true;
  } 
}

std::cout << "Desired present mode is not supported. Selecting default FIFO mode." << std::endl; 
for( auto & current_present_mode : present_modes ) {
  if( current_present_mode == VK_PRESENT_MODE_FIFO_KHR ) { 
    present_mode = VK_PRESENT_MODE_FIFO_KHR;
    return true;
  } 
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值