谢晓燕, 耿玉荣, 杨博文,韩孟桥
(西安邮电大学 a. 计算机学院; b. 电子工程学院, 西安 710121)
随着图形计算机产业领域的快速发展,相关图形应用编程接口(Application Programmig Interface, API)类型在不断更新。传统的图形应用程序开发是基于一定的图形API在其专用图形处理器上实现加速渲染[1-2]。但是这种“一对一”的操作会给图像应用场景的复杂度和高清化带来一定的局限性。因此,开发一种可兼容多种API类型的图形库正在形成一种趋势,以此满足更高效和更灵活的图形处理器需求[3]。
与图形处理器配套的图形API库有很多,如应用在移动设备上的OpenVG[4]和OpenGL ES[5]。OpenVG主要面向高质量2D矢量图形算法加速技术的便携手持设备,具有更好的图形渲染效果和更高的图形场景复杂度[6-7]。但由于OpenVG图形渲染的局限性,致使其无法完成OpenGL ES的3D渲染功能。OpenGL ES是OpenGL三维图形API的子集,可以实现基于三角形图元的3D图形渲染,主要针对手机、PDA和游戏主机等嵌入式设备而设计的[8-9]。为了使应用场景中支持二维矢量图形和三维图形的渲染实现,科研人员进行了相关的研究。如文献[10]中介绍了在OpenGL ES 1.x硬件加速器上实现对OpenVG 1.0的渲染加速。此设计充分利用了当前嵌入式系统中的OpenGL ES 1.x硬件加速器,在不需要额外增加OpenVG 1.0硬件加速设备的前提下实现对OpenVG 1.0的加速渲染,且具有突出的低功耗特性。文献[11]中是在总结了OpenVG支持的4种绘制模式上,提出在OpenGL ES的3D图形管道上使用GLSL ES片元着色处理器的实现方法。但这些扩展方案带来大量的计算,造成存储及运算资源的增加,从而导致渲染性能较差和渲染速度较慢,不适合移动设备的应用领域。
综上,本文针对GPU设计了一种通用图形API库[12]。在自主设计的图形处理器上,通过分析OpenGL ES 2.0和OpenVG 1.1两种图形库标准,采用了一种包含通用管理层、函数容错预处理层和命令解析层的3层抽象结构来实现通用图形API库的设计。以Linaro操作系统和Zync-7000[13]系列芯片XC7Z045FFG900-2 FPGA搭建了软件验证平台,通过编写测试程序对所设计的图形API库进行验证。
如图1所示,通用图形API库由通用管理层、函数容错预处理层和命令解析层3层抽象结构组成。应用程序使用OpenGL ES 2.0或者OpenVG 1.1图形标准绘制图像,API函数调用兼容两种图形API的通用图形API库,经过通用管理层封装OpenGL ES 2.0和OpenVG 1.1的共享API函数库;由函数容错预处理层完成图形上下文的建立以及图形函数参数的校验和处理;再由命令解析层根据所定义的函数指令集完成对API函数及其参数的命令转换,所设计的通用API库的指令集由148位的二进制数组成,包含10位命令字、10位控制码和128位数据位。最后通过驱动程序[14-16]将API函数指令交付给底层硬件处理器,从而达到对图形绘制加速的目的。
图1 图形系统的分层组织结构
通用管理层用于管理和封装OpenGL ES 2.0和OpenVG 1.1两种API函数库。为了更好的对不同类型的API进行区分调用,本文采用条件分支和函数索引表的编程思想进行设计,这种设计可以方便API库的管理和维护。首先判断图形API的类型,即OpenGL ES或者OpenVG。然后通过两个相互独立的索引表来分别表示OpenGL ES和OpenVG的API函数索引项。其中ES_Cur_Pointer是指向OpenGL ES当前函数索引表的指针,而ES_Dis_Table是由其函数指针组成的函数索引表。同理,VG_Cur_Pointer是指向OpenVG当前函数索引表的指针,而VG_Dis_Table是由其函数指针组成的函数索引表。其伪代码如下:
Algorithm1Common Management
1.if(OpenGL ES 2.0 Function Type)
2. *ES_Cur_Pointer;
//Point to function index table
3. Function implementation;
4.else(OpenVG 1.1 Function Type)
5. *VG_Cur_Pointer;
//Point to function index table
6. Function implementation;
7.endif
上述伪代码具体的实现过程如下:上层应用程序首先判断出用户调用的API函数是所设计通用图形API库中OpenGL ES 2.0或者OpenVG 1.1的函数类型,其次根据条件类型判断结果用函数宏定义找到函数索引表的当前指针ES_Cur_Pointer或者VG_Cur_Pointer,然后由当前指针找到该函数的具体功能实现即函数体部分,最后由图形加速处理器执行该函数体,并完成上层应用程序所分配的具体任务。
为了提高软件库的稳定性,函数容错预处理层需要进行函数状态检测和容错处理。函数容错预处理层采用上下文机制管理OpenGL ES 2.0和OpenVG 1.1图形API库的状态信息。其中图形API库中的上下文用一个Context结构体表示,该结构体包含函数索引表、驱动函数表、矩阵变换参数、渲染列表状态、缓冲区属性、错误反馈标志等状态信息。上述所有的状态信息将会在通用图形API库预处理过程中完成初始化,并且当上层应用程序调用状态信息查询命令时,会返回当前的状态值。
函数容错预处理层采用错误反馈机制,能够对用户编写的应用程序的语法错误进行一系列简单的处理,同时方便编程人员对该API函数库的管理。当用户编写的应用程序所输入的函数参数和图形API库中的函数参数不匹配或者格式不符时,在程序执行的过程中将会跳过出错的API函数并且将错误反馈给应用程序编写者,通过这种机制可以有效的提高图形API库的稳定性。函数容错预处理层的工作流程如下:
首先获取上下文状态信息,完成OpenGL ES 2.0或者OpenVG 1.1图形API库的初始化。当对应用程序的调用状态进行查询时,会返回当前的状态值。然后进行函数参数正确性的检测和错误处理,通过条件分支语句对函数参数的正误进行判断处理。函数参数的验证是通过Para_Check函数进行判断的,其伪代码如下:
Algorithm2Function Parameter Validation
1.VoidPara_Check(char des[],
char src[],
int pos)
2. inti= 0; intj= 0;
3.if(pos == D0) //Correctness check
4.for(i= 0;i< 32;i++)
5. des[i] = src[j];
6.j++;
7.elseif(pos == D1)
8.for(i= 32;i< 64;i++)
9. des[i] = src[j];
10.j++;
11. …
12.elseif(pos == D4)
13. …
14.elseReturn Error ;
上述伪代码具体的实现过程如下:如果用户输入的函数参数是正确的,则在上下文中管理对应的函数参数并调用命令解析控制层对应的函数,并在命令解析层完成API函数参数转换成特定格式的命令标识符;如果用户输入的函数参数是错误的,则程序在处理的过程中会直接忽略出错的API函数,并在程序执行结束后将错误信息反馈给程序用户输入者。
为了将函数功能参数转换为底层硬件可以识别的指令序列,设计命令解析层负责OpenGL ES 2 .0.或者OpenVG 1.1的API函数转换成指定格式的命令标识。OpenGL ES 2.0和OpenVG 1.1图形API库的指令集是由148位的二进制数组成的,从高到低分别是命令字(147-138)、控制码(137-128)和数据段(127-0),如图2所示。
图2 指令编码格式
命令字用于识别OpenGL ES 2.0和OpenVG 1.1函数库接口以及不同的API函数命令,控制码用来指定数据组织和存储格式即函数参数的个数以及参数的数据类型,数据段用来按控制码段指定的格式命令存储和传递要使用的参数,其中包括参数Data3、Data2、Data1和Data0。
如将OpenGL ES 2.0的函数glClearColor(GLclampf red,GLclampf green, GLclampf blue,GLclampf alpha) 转换成148位的命令标识符,具体转换过程如下:
(1) 查找函数glClearColor的命令字码,通过查找命令字码表可得命令字是0110000100。
(2) 查找控制字(Ctrl),通过查找函数glClearColor对应的控制字表可得控制字是0100000011;Ctrl[2:0]表示函数参数的数据类型控制字(见表1)。
表1 函数参数数据类型
(3) 函数参数red、green、blue、alpha分别转换为32位二进制数,分别作为参数D3、参数D2、参数D1、参数D0。所有的图形API函数均采用类似的方法进行编译。
函数glClearColor(GLclampf red,GLclampf green, GLclampf blue,GLclampf alpha) 在命令解析层的处理流程图如图3所示,部分伪代码如下:
Algorithm3Command parsing
1.VoidglClearColor(GLclampf red,
GLclampf green,
GLclampf blue,
GLclampf alpha)
2. code_init(); //initialization
3. float_to_fixed(red, para);
//Data conversion
4. … …
5. para_cat(glcode, para, D0);
//Get function parameters
6. … …
7. get_ctrl(ctr, 10); //Get the control code
8. opcode_cat(glcode,CLEARCOLOR);
//Get the command word
9. save_Data(); //save data
图3 命令解析层处理流程图
为了区别OpenGL ES 2.0和OpenVG 1.1两种图形API函数库,将命令字段的最高位作为区别标识符。若命令字段最高位置0,则表示OpenGL ES 2.0的API函数;若命令字段最高位置1,则表示OpenVG 1.1的API函数。每一条指令对应唯一一组命令编码,用于区分不同的命令;由于有些命令的参数比较多,可能需要2条或3条命令才能传送完成,控制字用于指示是否为最后命令的最后一条。
本文所提出的移动图形处理器(Mobile Graphics Processor,MGP)硬件设计如图4所示,主要包括CPU_IF模块、前端处理器(Front End Processor,FEP)、统一架构染色器(Unified Shading Processor,USP)、屏幕坐标产生单元(Screen-coordinate Generating Unit,SGU)、Tile产生单元(Tile Generating Unit,TGU)、帧缓冲区(Frame Buffer,FB)等处理模块。其中CPU_IF模块负责与主处理器的数据、状态、控制信息的交互,支持AXI总线协议,并完成总线数据与图形处理硬件的信号同步。FEP模块负责图形渲染任务的分解、组织与初步调度。FEP以可编程形式解析OpenGL ES 2.0和OpenVG 1.1的图形API命令。
图4 移动图形处理器体系结构
使用vivado 2015.4集成设计工具将移动终端显示控制芯片IP核电路设计封装成有AXI接口的自定义IP核[17],通过制作SD卡启动镜像,将封装好的IP核做为协处理器挂载到Zynq-7000开发板的ARM Cortex-A9处理器上。驱动程序将指令数据存储在开发板的外部存储设备DDR3中,并在处理系统(Processing System,PS)端完成数据的读取和写回控制,在可编程逻辑(Programmable Logic,PL)端完成图形渲染处理,如图5所示。
图5 系统总体架构图
CPU_IF模块通过AXI总线读取DDR3中的图形API指令,然后将指令透传到FEP模块进行命令解析和下一步的渲染操作。
采用通用管理层、函数容错预处理层和命令解析层的3层抽象结构来实现通用图形API库,由于软硬件存储指令方式的不同需要由驱动程序对指令序列进行数据进制的转换。所设计的通用图形API库在命令解析层处理完成后,生成148位的二进制数据。驱动程序将命令解析层传递下来的148位二进制数据流转换成五部分,每部分由32位二进制数据组成。因为五部分32位二进制数据为160位数据比传递下来的148二进制数据流多12位,所以通过高位补零的方式将命令字和控制码字段合并为一个32位二进制字段,如图6所示。再将转换过的数据存储在Zynq-7000开发板PS端的DDR3中,DDR3作为外部缓冲区。同时要将二进制指令在外部缓冲区中的存储地址和指令条数分别写入GPU内部的渲染列表基址寄存器和渲染状态字寄存器中。MGP会根据这两个寄存器中存储的地址以及命令条数在外部缓冲区DDR3中读取相应的渲染命令,完成软件到硬件的数据通信。
图6 指令转换
MGP内部的控制命令寄存器会根据指令存储地址在指令缓存区中读取启动渲染操作指令,在由MGP处理完成后,根据写回源选择寄存器中的地址值写回到帧缓冲区对应的地址中,再由显示设备读取帧缓冲区中的像素数据,完成图形显示操作。
本文采用Linaro操作系统和Zynq-7000系列芯片XC7Z045FFG900-2 FPGA搭建了软件验证平台,通过编写大量测试程序在图形处理系统上对其进行测试,以此来验证对所设计图形API库正确性。
为了验证所设计的通用图形API库的正确性,编写大量的测试例子对图形库进行测试。图7所示为使用OpenGL ES 2.0编写的图形应用程序,其中图7(a)是使用本文所设计通用图形API库绘制的测试例子,图7(b)是使用标准的图形库进行绘制的。图8(a)是使用所设计的图形库对OpenVG 1.1蓝色正方形例子的测试,图8(b)为标准的OpenVG 1.1绘制的图形。
(a)(b)
图7 OpenGL ES 2.0绘制图形比较
测试表明本文所设计的通用图形应用编程接口库可以满足OpenGL ES 2.0和OpenVG 1.1基本函数功能的渲染操作。
(a)(b)
图8 OpenVG 1.1绘制图形比较
对测试图形进行渲染数据分析,如表2和表3所示。
表2 OpenGL ES 2.0绘制数据分析
表3 OpenVG 1.1绘制数据分析
数据表明本文所设计的通用图形应用编程接口库绘制性能能够满足基本图形绘制的需求。
本文基于自主设计的移动GPU硬件架构设计了一种的通用图形API库,在满足图形渲染性能和速度的前提下,通过分析OpenGL ES 2.0和OpenVG 1.1两种图形库标准,采用了一种包含通用管理层、函数容错预处理层和命令解析层的3层抽象结构来实现通用图形API库的设计,并以Linaro操作系统和Zynq-7000系列芯片XC7Z045FFG900-2 FPGA搭建了软件验证平台,完成了对所设计图形API库的验证,实现了基本图形的渲染操作。