Imagination 关于motion to photon latency延迟的解决方案 --VR

虚拟现实需要现代手机中的许多组件的支持。从用于记录头部移动的传感器、CPU运行VR应用(并在后台运行其他程序)、然后GPU开始工作并计算创建为VR图像修正后的图像,最终呈现到屏幕上。
所有这些组件需要紧密合作来创造出大家所说的身临其境的体验。实现这些功能所需的时间一般叫做motion to photon latency(从用户运动开始到相应画面显示到屏幕上所花的时间)。尽管这是一个很普通的术语,但是它很好地描述了这个问题:当我头部运动时所产生的场景变化,需要多久才能被我的眼睛所接收,并最终被我的大脑所理解。
在现实生活中这会实时发生,否则你将会一直撞到墙上去。然而,用手机绑到头戴显示器来创造出类似的效果却是非常困难的。这有很多原因:电脑运行在固定的时钟、流水线序列化数据处理的时间以及渲染最终图像的时间。
作为一个GPU IP公司,我们关注优化我们的Graphic Pipline,以此减少用PowerVR处理器来渲染内容直至它们展现到屏幕的时间。

安卓系统的图像合成要求
安卓的最终屏幕上的输出是使用composition 来渲染。通常各个图像有各自的组件负责,例如SystemUI负责导航栏和状态栏,然后前端应用将内容渲染到缓冲。
这些缓冲区由客户端来排列到屏幕上显示。大多数时候这个客户端是一个叫做SurfaceFlinger的系统应用。如果硬件支持的话,SurfaceFlinger会选择将缓冲区直接显示在屏幕上。这种被称为Hardware Composition的模式需要显示硬件的直接支持。如果显示器不支持某个特定的安排,SurfaceFlinger会通过GPU用一个屏幕大小的Framebuffer并渲染所有正常状态的图像到那个Framebuffer。最终的图形会被合成并显示到显示器上。
这里写图片描述

Poducer和Consumer都是高度互相独立的。事实上,他们甚至常常是不同的进程,通过跨进程通讯来沟通。如果其中一方不小心,所有的这些不同的进程会一直互相干扰。
举个例子,producer可能会渲染一个buffer到正在显示中的缓冲区。如果这种情况发生,用户会看到手机上画面显示不正常。我们称之为撕裂。屏幕的一部分仍然显示旧的内容,另一部分已经显示了新的内容。这种情况很容易辨认,只要看到切开画面的一条线,很有可能就是由于撕裂产生的。
![这里写图片描述](http://p3.pstatp.com/large/71f000487533a777862)

例如,生产者可能会渲染到当前展示给用户的缓冲区中。如果这种情况发生,用户的手机会看到这个作为一个视觉冲突称为撕裂。屏幕的一部分仍然显示旧的内容,另一部分已经显示了新的内容。看到切线以后,撕裂是很容易辨认的。
为了防止撕裂,2个关键要素是必要的。第一个是所有方面的同步,其次是双缓冲。

同步是通过使用一个叫做Android Native Syncs的框架来实现的。Android原生同步有一定的标准,这些标准在被Android使用的系统中是非常重要的。Android Native Syncs是全球同步系统,应用在很容易共享不同程序的内存空间中。
它们也是不能重复使用的二进制同步,只有两种状态“无信号”和“有信号”,并且只可以从“无信号”转变到“有信号”。
当旧的内容仍被消费者使用时,双缓冲允许生产者提供新的内容。当生产者已完成渲染,这2个缓冲区切换,消费者可以呈现新的内容,而生产者开始渲染到旧内容缓冲区。
对于Android用户界面的流动输出来说,这两种机制都是必要的。但不幸的是,他们也有一个额外的延迟的成本。
拥有双缓冲意味着现在渲染好的内容可以在后一个框架内可见。同时,同步可以防止访问屏幕上的任何东西。为了消除这种特殊的延迟,可以使用单一缓冲的想法。这意味着渲染总发生在屏幕上的缓冲区,并且显然,同步也需要被关闭。
在三月,我们将这个特征应用在Khronos Group批准的KHR_mutable_render_buffer EGL extension项目上面。
这个扩展需要GPU驱动和Android操作系统的共同支持。正如我之前解释的,由于会导致撕裂,安卓系统需要很长一段时间来以防止这种模式的运作。
那么,在新的单缓冲模式下运行时,我们如何才能防止撕裂?
屏幕技术
要回答这个问题,我们需要理解显示器是如何工作的。GPU驱动抛给显示器驱动一个显示器可以理解的格式的buffer。对buffer内存的格式要求可能有不同,如special striding或tiling alignments.。
显示器通常会将这个新的buffer显示在下一个垂直同步。假设显示器从上到下逐行显示这个内存。Vsync就是从下回到屏幕顶部的那条线的时间点。显然现在的显示器已经没有这条扫描线了,但是这个术语仍然在使用。因为在这个时间点上,显示器不扫描任何buffer,在这个时候切换到一个新的buffer不会造成画面撕裂。显示器在屏幕显示周期内会在固定的时间间隔里持续重复这个步骤。
这里写图片描述

一个普通的屏幕周期为16.7ms。这意味着图像在屏幕上每秒钟更新60次。
现代手机通常是16:9的纵横比,并且屏幕显示方向被优化为更适合竖立显示的模式。
因为把部分时候,用户是竖着使用他们的手机的。但对于虚拟现实应用,常常是使用的横向显示的模式。这对于我们如何更新任然在显示中的画面非常重要。Strip rendering
当显示器显示buffer时。它会运行在一个固定的频率。Strip rendering的想法就是,改变还没有显示出的那部分buffer。有2种不同的策略可供选择。我们可以改变下一步将显示的屏幕的那部分。
这我们称之为beam racing。因为我们想要跑在扫描线前更新还未被显示的那部分内存。另一种策略称为beam chasing。Beam chasing 在扫描线后更新画面。
对于优化延迟这个目的来说,beam racing策略会更好,但是同时也更难实现。GPU需要保证在很紧的时间窗口完成渲染。这非常难保证,尤其是在一个多线程的操作系统中,所有运作都发生在后台,同时,GPU可能会渲染到其他buffer的区域中。所以Beam Chasing会更容易实现。
这里写图片描述

VR 应用取得显示的上一个Vsync 的时间,来调整自己以保证自己有渲染整个画面的时间。为了计算开始渲染的时间。我们需要条的尺寸。strip的尺寸,和使用多少strip,在执行时被定义。这取决于画面需要多久被显示,和我们需要多久去渲染这个画面。在多数情况下,2条是最合适的。
在VR中,这还有个优点,就是一个眼睛一个strip。(我们可以从做渲染到右边)。这使得实现更容易一点。在接下来的例子中,我们任然使用4个Strip来展示这通常是怎么工作的。如我更菜所说,我们有16.7ms来渲染整个画面。
![这里写图片描述](http://p1.pstatp.com/large/7230005f43cfa997845)

 因此,我们有4.17ms来渲染每一个strip。VR应用在上一个Vsync之后需要等待4.17ms然后开始渲染新的strip。然后在渲染第二个strip前等4.17秒(距离上一个vsync 8.34ms),这一直重复直到四个线条都被渲染然后再来一遍。显然我们需要考虑每个渲染需要的时间然后相应地调整时间。使用绝对时间已被证明是最准确的方法。

最后的思考
在移动设备中减少VR的延迟,是如今的开发人员面临的主要挑战之一。这与台式VR的解决方案是不同的,台式VR的解决方案通常有更快的处理速度并且对于热量也没有移动端那么大的限制。

转载 AR酱
链接:http://toutiao.com/i6290882882374205954/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值