PowerVR成像框架内支持零拷贝流

在先前的一篇文章中,我介绍了PowerVR成像框架,即OpenCL和EGL API的扩展,其可使PowerVR GPU和其他系统部件如CPU、ISP和VDE之间实现有效的零拷贝内存共享。

大多数流使用EGL来促进多个客户机API之间的对象共享,这便需要Khronos扩展CL_KHR_EGL_IMAGE。以下示例展示了PowerVR成像框架内支持的不同的零拷贝流。

本地YUV半平面图像的GPU采样

下图展示了硬件组件将YUV半平面图像写入内存的配置,该配置使用Android gralloc缓冲区,且GPU直接对亮度和色度值采样。

本地YUV半平面图像的GPU采样

主机代码应两次调用eglCreateImageKHR,以将Gralloc缓冲区的两个EGL图像实例化。以0(用于Y面)和1(用于UV面)两个值来传递选项EGL_NATIVE_BUFFER_MULTIPLANE_SEPARATE_IMG和CL_NATIVE_BUFFER_PLANE_OFFSET_IMG。

随后,主机应调用CL Create From EGL Image KHR,以将两个OpenCL图像实例化(image2d_t型)。

OpenCL内核应该在这两个图像上调用read_imagef (或read_imagei)来取样像素值。抽样第一个图像将返回一个float 类型的 4 元素变量。在这个变量中,第一通道包含一个含CL_UNORM_INT8的元素。第二个图像采样将返回一个float 类型的 4 元素变量。在这个变量中,头两个通道包含一个含CL_UNORM_INT8类型的元素。

平台必须支持OES_EGL_image_external和EGL_IMG_image_plane_attribs的扩展。

本地YUV平面图像的GPU采样

下图展示了硬件组件将YUV平面图像写入内存的配置,该配置使用Android gralloc缓冲区,且GPU直接对亮度和色度值采样。

硬件组件将YUV平面图像写入内存的配置

主机代码应三次调用eglCreateImageKHR,以将Gralloc缓冲区的三个EGL图像实例化。以0(用于Y面)、1(用于U面)和2(用于V面)三个值来传递选项EGL_NATIVE_BUFFER_MULTIPLANE_SEPARATE_IMG和CL_NATIVE_BUFFER_PLANE_OFFSET_IMG。

随后,主机应调用CL Create From EGL Image KHR,以将三个OpenCL图像实例化(image2d_t型)。

OpenCL内核应该在这三个图像上调用read_imagef (或read_imagei)来取样像素值。抽样每个图像将返回一个float 类型的 4 元素变量。在这个变量中,第一通道包含一个含CL_UNORM_INT8的元素。

平台必须支持OES_EGL_image_external和EGL_IMG_image_plane_attribs.的扩展。

YUV图像作为RGB处理的GPU采样

下图展示了硬件组件将YUV半平面图像写入内存的配置,该配置使用Android gralloc缓冲区,且GPU采样数据将保存为RGB。Rogue硬件(TPU块)可自动将采样的YUV数据转换成RGB动态数据。

硬件组件将YUV半平面图像写入内存的配置

主机代码应调用eglCreateImageKHR,以将EGL图像实例化,不用在属性列表中添加附加标记,并启用CL_IMG_YUV_image扩展。随后,主机调用clCreateFromEGLImageKHR,以将OpenCL图像实例化(image2d_t型)。

OpenCL内核应该在这个图像上调用read_imagef (或read_imagei)来取样像素值。抽样图像将返回一个float4 RGB变量。在抽样过程中,硬件进行了必要的色彩空间转换。

平台必须支OES_EGL_image_external和CL_IMG_YUV_image的扩展。

支持的YUV格式如下表:

Format

Description

NV12

4:2:0 8-bit

Semi-planar u/v

NV21

4:2:0 8-bit

Semi-planar v/u

YV12

4:2:0 8-bit

Planar Y/V/U

I420

4:2:0 8-bit

Planar Y/U/V

Android相机HAL的GPU采样

前面小节中的示例展示了如何通过硬件配置GPU来直接从个人图像输出中取样,例如,通过相关的Android HAL(硬件抽象层)直接连接摄像机或视频驱动程序。Android提供了一个缓冲区队列API来支持摄像头和视频应用程序。下图展示了硬件组件将序列图像流入内存中的配置,该配置使用了Android缓冲列队,且GPU从这个队列中读取图像。

Android相机HAL的GPU采样

缓冲区队列API为生产商和消费者均提供了接口。主机代码应该首先初始化硬件(摄像机或视频解码器),并对缓冲区列队的生产商接口进行相关的处理。随后,从硬件中对图像进行流处理,这可使用消费者接口来获取下一个Gralloc缓冲区以进行处理。应使用上文所述的OpenCL和EGL扩展来创建可以从GPU上的OpenCL 中取样的image2d_t对象。Google 将Android缓冲区列队API定义为隐私的区域,不曝光在Android SDK或NDK中。因此,为了进行集成,平台厂商应该允许访问此API或提供另一个可在内部使用API的接口。

在CPU和GPU中共享OpenCL缓存

PowerVR Rogue设备能够分配内存,其也可以映射和共享CPU。然而,Rogue设备目前无法任意将主机分配的CPU内存映射到GPU。因此,为了在CPU和GPU之间共享内存对象,主机应该创建使用CL_ALLOC_HOST_PTR标志的对象和使用映射函数clEnqueueMapBuffer、clEnqueueMapImage和 clEnqueueUnmapMemObject的访问通道。

下图显示了如何将CPU分配的缓冲区传给GPU。首先,主程序对CPU分配内存中的两页数据进行分配和初始化。然后再调用clCreateBuffer,将指针传递给这个数据和CL_USE_HOST_PTR。

如何将CPU分配的缓冲区传给GPU

一般来说,这些页面的数据不能被GPU寻址。且即使GPU可寻址页面,当虚拟内存需要其他页面时,CPU也可能自由交换页面到磁盘上。因此,当主机程序入列操作数据的内核时,驱动器首先将在GPU分配的内存中分配一块内存,并在运行内核之前创建一个数据副本。每次数据在主机和设备之间传输时,这种复制操作都需要带宽成本,这将明显降低性能,但却可保证正确的操作程序。例如,下图显示的情况是,在内核执行时,CPU上运行的操作系统互换了页面的一些原始分配内存到磁盘上。

CPU上运行的操作系统

这里,我们展示了备用情况,即主机程序在GPU分配内存中分配缓冲区。首先,主程序用CL_USE_HOST_PTR标识调用clCreateBuffer,即对GPU分配内存中的两页数据进行分配。然后将这些数据初始化。

对GPU分配内存中的两页数据进行分配

OpenCL映射和非映射函数用来传递CPU和GPU之间的缓冲区所有权。默认缓冲区是GPU缓存,CPU非缓存。这意味着主机实施的映射操作有一个冲洗GPU缓存的成本,但非映射操作没有成本。

创建一个CPU-cached的OpenCL缓冲,用CL_IMG_USE_CACHED_CPU_MEMORY_IMG标志调用clCreateBuffer函数。一般来说,当CPU需要通过GPU读取数据输出时,CPU-cached缓冲区则非常有用。正如输出缓冲区由GPU渲染图像到显示时,CPU-uncached缓冲区则非常有用。

扩展阅读

以下是已发布的有关异构计算的系列文章,以供参考:

• 异构计算移动系统指南
• 快速指南:为PowerVR Rogue GPU编写OpenCL内核
• 增加异构软件的性能和功效
• Android PowerVR成像框架
• 异构计算实例学习:图像卷积滤波
• 深度学习:使用PowerVR实现计算机视觉
o Part 1: o 计算机视觉算法
o Part 2: o 计算机视觉的硬件IP
o Part 3: o PowerVR的OpenCL人脸检测
• PowerVR成像框架相机的演示
• PowerVR成像框架内支持零拷贝流
• 测试GPU计算性能
• Imagination用于移动计算的智能高效方法
• PowerVR异构计算的完整术语

原文链接:
http://blog.imgtec.com/powervr/supported-zero-copy-flows-inside-the-powe...

--电子创新网--
粤ICP备12070055号