原帖地址:Do Androids have nightmares of botched system integrations?
发帖人 davidsben 2014 5:09:15 PM于2014年2月11日17:09:15在ARM Mali Graphics
ARM 在今天发布了 ARM® Mali™-DP500 Display 显示处理器,这是 ARM 迄今为止开发的第一款高规格显示处理器。除了显示处理器本身外,ARM 还将提供针对 Android™ HW Composer HAL 的优化软件驱动程序,为基于 Mali-DP500 的 Android 设备带来平滑顺畅的用户体验。
正如下文所述,通过将 Mali-DP500 加入到 ARM 的媒体处理产品组合中,可以让依靠 ARM 产品搭建的平台在系统集成上向前跨越一大步;但对于 ARM 的软件驱动程序团队而言,这只是 2009 年 Android Éclair (2.1) 在 ARM Mali-200 开发平台上崭露头角后我们进取道路上的又一步而已。
自大约五年前的那天起,ARM 的软件驱动程序团队已经把对 8 个不同版本 Android(从 Éclair 到 KitKat)的支持添加到我们驱动软件包的 13 个版本中(运行在 7 代 Mali GPU 硬件之上),并协助将这些驱动程序部署到数百种不同设备上,包括对 Google Nexus 10 上最尖端的 Android 系统的贡献。这可不是小小的成就,而且,在如此长时间为 Android 提供支持的过程中,我们的软件团队已经在操作系统方面累积了丰富的经验,不仅是在 GPU 子系统方面,还涉及整个媒体子系统,包括渲染、合成、视频与摄像头等,虽然 GPU 在这些系子统中只起到了一部分作用(但很大又重要)。
我们发现,客户在努力将一个供应商的视频、另一供应商的摄像头 ISP、ARM 的 GPU 以及自己的显示解决方案集成到 Android 中时,面临诸多难题。所以,我们指导许多客户制定出解决方案,将他们的系统转变为性能一流、真正漂亮美观的 Android 系统。通过这些不同的客户经历,我们已经对什么才是完全集成的媒体子系统驱动程序有了清晰的认识,也清楚它们必须支持什么样的功能,才能让任何平台都能在 Android 上实现最佳的性能和功耗。
在这一点上,我觉得一张图片抵得上千言万语。尤其是下面这张图,你可以从中发现,工程师其实把成百上千个工时花在了系统集成之外的工作上:
上图实际上已经过简化(没错,现实情况更糟),显示了 Android用户空间通用组件与底层软件驱动程序、内核组件以及用于提供 Android 用户体验的硬件之间的各种交互。如果你的媒体组件分别来自不同的供应商,那么你最终需要三个(或更多)软件驱动程序。你首先需要将它们分别集成到平台之中,然后还必须将它们互相整合,以便能获得不错的系统性能。如果集成得不对,或者不同组件没有使用相同标准的接口进行通信,那么你只能获得一个功能尚可的平台,而且不是速度太慢就是功耗过高,甚至最糟糕时这两方面的表现都差强人意。
ARM 对经常在客户平台上看到的常见集成难题进行了思索和设计,通过开发一系列能够集成和协同运行的驱动程序攻克了这些难题。接下来,我们看看客户面临的真正问题,以及我们的预集成解决方案如何帮助避免这些问题:
系统集成期间的一件大事,是要确保媒体子系统(即视频、GPU、摄像头或显示屏)中的每一组件都能真正理解它从其他组件读取的的图形输出的格式,并且每个组件都能使用其他组件能够读取的格式生成内容:
这些只是我们发现的实际集成问题中的几个例子,它们都可以通过使用我们的完整解决方案予以避免:每一 ARM 组件都已设计为能够互相配合并能在 Android 中运行,让你不用在最后一刻还要对它们是否使用相同的语言而困惑。此外,ARM 除了提供自己的软件驱动程序外,还提供一个开源分配库 (Gralloc),它已设置为支持我们的所有组件,从而进一步缩短部署实施的时间。
对于在何处以及如何为系统的图形缓冲分配内存所做的决定,也经常引起很多问题。在分配内存时,你需要考虑访问该内存的底层硬件的各种局限。在集成组件时,你必须要能够回答以下关键问题:
ARM 提供的 Gralloc 库本身就清楚 ARM 的多媒体处理器的所有系统局限,能够和 Android 内核的 ION 分配器搭配运行,确保为系统中的每一处理器进行最适当、最高效的内存分配。
此外,ARM 多媒体处理器的每一种软件驱动程序都利用标准的 Linux dma_buf 内存共享功能。通过确保所有驱动程序使用相同的接口,相同的分配可以由一个处理器写入而被另一处理器读取,为平台上的所有图形和视频内容提供“零拷贝”路径,确保内存带宽开销尽可能保持最低。
当你的系统中有“零拷贝”路径,并且有两个以上设备直接使用同一段内存时,这些组件间的同步就变得异常重要。你肯定不希望显示处理器在 GPU 或 Video 处理器完成对某一缓冲的写入前就开始从中读取,否则会出现一些烦人的屏幕画面异常问题。
在较早版本的 Android(Jellybean MR1 之前)中,同步是在 Android 用户空间中处理和控制的,其方式是让渲染管线中的每一组件都执行下列步骤:在软件驱动程序中处理其命令,在硬件中执行其任务,等待该任务在软件驱动程序中完成,然后将职责传给管线的下一阶段。这在组件之间实现了一种非常简单和方便的同步方式,但也在渲染管线中造成了大量气泡(空隙),因为 CPU 和硬件之间会持续出现停顿和来回作业,而且您必须要等到上一阶段的硬件处理完成后才能开始下一阶段的 CPU 处理。所有这些管线停顿也就决定了最终用户体验是“顺顺畅畅”还是“磕磕巴巴”。
到了 Jellybean MR1 时,Android 平台中加入了一种新的同步方式,即 Android 围栏(Android fences)。这些围栏如果得到软件驱动程序的支持,将允许管线中的每一阶段执行其 CPU 端的处理,同时为其组件排列作业队列(即使上一阶段的硬件处理尚未完成),并在其自己的硬件处理完成(甚至开始)之前将控制传递给管线的下一阶段。管线中的每一组件完成其工作时,它将发出围栏信号,下一阶段将自动触发,CPU 只需很少的参与。如此一来,在作业链中,从一个硬件完成作业到下一个硬件开始作业之间的间隙将大幅缩短,为系统挤出所有可用性能。为了充分利用 Android 围栏的优点,渲染管线中的每一组件都需要支持它们。如果有一个组件不支持,那么管线中的相应阶段将退回到用户空间中等待,系统便会出现性能气泡。
然而,当所有组件都支持 Android 围栏但其中一个存在错误时,就会出现大问题。此类错误的唯一显现方式是系统中突然出现一个图形错误随即又立刻消失。现在你能做什么?你有三个或更多不同供应商提供的软件驱动程序,它们都支持 Android 围栏,而其中一个出现了错误,但如何知道是其中哪个呢?如何进行追踪?要了解清楚,你必须与供应商展开三个独立的调查,尝试找出只有在一个供应商的组件使用标准接口与另一供应商组件通信时才会显现出来的一个错误。像这样寻找错误的难度极大,尤其是当各家供应商都不了解其他供应商的软件时。这些错误会让你设备的发布日期一拖再拖,因为你得一直等,直到有人告诉你“找到了”。幸运的是,这并不是你的唯一选择;如果你采用 ARM 的完整解决方案,那么你就拥有了一套已经过实施,甚至经过验证可正确运行的驱动程序;当确实发现问题时,你也只需要和一家供应商协商,而且你也可以相信他们具备所有必要的专业技能,能够快速找到问题并加以解决。
系统集成不仅仅是为了避免问题,同时也是为了将数个组件组合在一起,实现一加一大于二。ARM 的全新 Mali-DP500 是一款为充分发挥 Android 效用而精心打造的产品,能够高效地分流 GPU 上的合成作业。我们已经对 Android 产生的常见合成场景进行了细致的调查,发现 Android 市场上大多数应用程序和游戏使用三个以下图层,通常最多也就四到五个图层。
任何合成引擎必须权衡其支持的硬件层数量以及芯片面积/成本。当合成帧所用的图层数量超出硬件支持范围时,任何多出的图层通常需要使用 GPU 将它们平面化到一起再进行处理。Mali-DP500 软件驱动程序通过完整控制哪些图层发送到 GPU 进行平面化来应对这个问题,这可以让我们利用如何充分发挥 GPU 效用方面的专业知识。Mali-DP500 软件驱动程序将根据 Android 生成的场景,智能地决定将什么内容发送到 GPU,以便与在 GPU 上执行完整合成相比,尽可能减少需要使用的带宽和功率。
当系统 GPU 中部署了事务消除 等技术时,Mali-DP500 软件驱动程序可以确保 GPU 仅处理静态或不常变化的图层,使 GPU 写入这些图层到内存时所用的内存带宽有效降低到接近于零;与 GPU 中的 AFBC 技术搭配时,即便 GPU 必须实际处理非静态内容,所用的内存带宽也将大幅降低。
所以,这就是解决方案。随着面向显示和视频的优化驱动程序的加入,加上我们已经为 GPU 提供的一切,ARM 现在能够提供一整套经过预集成与优化的现成驱动程序。最重要的是,它们都已经过验证并符合 ARM 的最高质量标准,在你的平台准备好首次运行软件*之前*,便已能够无缝搭配运行。
如此一来,在 Android 上进行系统集成时,再也不必纠结于稳定性与性能之间的权衡利弊,也不用担心陷入供应商繁多、难以协调的噩梦之中。Android 开发者们可以再一次平静地梦见”羊”了。