Adreno OpenGL ES 3.1 介绍(1)

175 篇文章 26 订阅
43 篇文章 6 订阅

4. 使用OpenGL ES 3.1与Adreno

4.1 OpenGL ES 3.1中的新特性

本节简要介绍了OpenGL ES 3.1中引入的一些重要特性。详情请参见以下内容:

4.1.1 原子计数器

OpenGL ES 3.1提供了一个新的无符号整型变量类,称为原子计数器。这些计数器可以通过着色器使用不同的原子操作来访问。这些操作的原子性质意味着当多个着色器调用试图同时访问一个原子计数器时,这些访问将被序列化,这样就不会发生线程竞争。

要在着色器中定义一个原子计数器,使用新的ES着色语言类型atomic_uint。该类型是不透明的,所以从着色器中访问或操作计数器值的唯一方法是使用一个新的访问函数,包括:

  • atomicCounter - 返回计数器的值
  • atomicCounterDecrement - 减少计数器的值并返回新的值
  • atomicCounterIncrement — 使计数器的值递增,并在递增操作之前返回该值

原子计数器必须得到缓冲区对象存储空间的支持。使用新的索引缓冲区对象绑定点GL_ATOMIC_COUNTER_BUFFER,将原子计数器与缓冲区对象的区域关联起来。允许多个原子计数器使用一个缓冲区对象,只要它们的存储空间不重叠或相交。

要将原子计数器与唯一的缓冲区对象区域关联起来,在声明原子计数器时需要使用两个新的布局限定符:

  • Binding - 指定缓冲区对象绑定点的索引,例如,它决定将使用哪个缓冲区对象,并且必须始终指定
  • Offset - 指定缓冲区对象内原子计数器的偏移量(以字节为单位)

有关使用这些限定符的更多细节,请参阅OpenGL ES 3.1着色语言规范http://www.khronos.org/registry/gles/specs/3.1/GLSL_ES_Specification_3.10.pdf

例如,假设任务是找出传入输入数据集的值中哪些是素数。可以通过实现一个计算着色器来解决这个问题。

单个计算着色器调用将获取唯一的工作组和工作项ID,将此信息转换为唯一的条目索引,并使用该索引来寻址输入数据集以检索候选编号。一旦调用知道要处理哪个值,它就可以继续执行必要的检查,以确定该值是否是素数。如果输入值确实是一个素数,那么计算着色器调用可以将它存储在外部存储器中。但是原子计数器是如何在这里出现的呢?

使用计数器作为获取索引值的一种方法,这些索引值将确保在已计划运行的所有计算着色器调用中是唯一的。使用OpenGL ES着色器语言指令递增原子计数器,在递增之前返回计数器的值。如果多个着色器调用同时尝试递增计数器,则可以保证这些请求将被序列化。一旦计算着色器调用获得了唯一的计数器值,它就可以使用它来存储在着色器存储缓冲区或图像中找到的素数,其偏移量不会被任何其他计算着色器调用覆盖。最后,一旦所有计算着色器调用完成执行,计数器值将用作找到的素数的计数。然后,应用程序可以将缓冲区对象区域或用于结果存储的纹理mipmap中的素数值传回进程空间。

注意:在核心opengles3.1中,只保证在计算着色器阶段支持原子计数器。
	在其他着色器阶段也可能支持它们,但情况并非如此。

4.1.2 计算着色器

OpenGL ES 3.1引入了一种称为计算着色器的全新类型的着色器。这些不构成正常渲染管道的一部分,可以使用GPU执行数据处理任务。

计算着色器的孤立特性会产生许多后果:

  • 不支持输入属性或输出变量
  • 不会像顶点着色器那样每个顶点调用一次
  • 执行之前或之后没有其他着色器阶段

但是,它们与常规着色器类似,因为它们可以访问原子计数器、图像变量、着色器存储缓冲区、纹理、uniforms和uniform blocks。

例如,计算着色器如何与外部通信?毕竟,它不能使用输入属性或输出变量。答案是它可以使用上面提到的对象类型。其中,只有原子计数器、图像变量和着色器存储缓冲区可以在着色器运行时写入。当计算着色器想要存储其工作结果时,它可以使用一个新的原子计数器函数,更新图像的内容,或者写入缓冲区变量。

由于计算着色器在正常渲染管道之外操作,因此它们不会通过绘图调用来调用。取而代之,新的glDispatchCompute函数用于启动操作。

在开始计算之前,必须把要做的工作分成几个工作单元。

每个单元由一个工作组处理。单个工作组由多个调用组成,这些调用可能并行处理该工作单元。使用的调用数由着色器定义。根据着色器的需要,在1D、2D或3D网格中安排调用。网格的尺寸定义了本地工作组的大小。对于本地工作组的最大规模,存在特定于实现的限制。

这些约束就是为什么工作通常必须被分割成多个单元的原因。glDispatchCompute接受一组参数,定义X、Y和Z维度中的工作组计数。这允许使用单个API调用启动对工作单元的三维数组的处理。回想一下,每个工作单元都可以由一个三维的着色器调用数组组成。

单个工作组内的调用可以使用新的ES SL函数groupMemoryBarrier同步它们的执行。它们可以使用共享变量相互通信。它们还可以使用可写对象(如图像)交换信息,前提是它们可以使用新的ES SL函数之一:barrier、memoryBarrier*或groupMemoryBarrier来同步访问。

关键点

重要的工作组可以以任何顺序执行,并且不保证并行执行。这意味着在不同工作组之间同步执行流或资源访问的任何尝试都可能导致死锁。不能在多个工作组之间通信或同步执行流,只能在同一工作组内的不同调用之间通信或同步。
计算着色器允许在工作的组织方式中有更多的灵活性,这要感谢共享变量,这在计算着色器中可用,但在其他着色器类型中没有。因此,它们越来越多地被用于人工智能、物理或后期处理效果。

提示
不要交叉使用计算着色器和图形着色器。在Adreno架构下,在这两种管道类型之间切换是昂贵的,应该避免。相反,批处理draw调用和dispatch调用以减少驱动程序必须切换的次数。

4.1.3 ES着色语言的一些增强功能

OpenGL ES 3.1着色语言引入了以下增强功能:

  • 现在绑定布局限定符可用于指定与uniform block或uniform采样器关联的初始绑定点
  • 将浮点数拆分为有效位和指数的函数(frexp)
  • 从有效位和指数构建浮点数的函数(ldexp)
  • 使用进位或借位执行32位无符号整数加减操作的函数(uaddCarry, usubBorrow)
  • 执行32位有符号和无符号乘法的函数,32位输入和64位结果跨越两个32位输出(imulExtended、umulExtended)
  • 执行位字段提取、插入和反转的函数(bitfieldExtract、bitfieldInsert、bitfieldReverse)
  • 现在可以在ES SL代码中定义多维数组
  • 现在可以通过一次调用确定整数值中设置为1的比特数(bitCount)
  • 现在可以通过一个函数调用确定将最高或最低有效位设置为1的位置(finddlsb, findMSB)
  • ES着色语言(textureGather,textureGatherOffset)中现已提供纹理收集函数;这些函数可用于检索2x2占位面积,用于在纹理查找操作中进行线性过滤
  • 将4个8位整数打包为32位无符号整数,并将32位无符号整数解包为4个8位整数的函数(packUnorm4x8, packSnorm4x8, unpackUnorm4x8, unpackSnorm4x8)
  • 通过使用位置布局限定符,可以直接在ES着色语言中预先配置默认uniform block中的uniform的位置

本章其他章节中涉及的ES阴影语言特性未在上述列表中体现。

OpenGL ES 3.0 英文版 第1章——OpenGL ES 3.0简介   第1章简单介绍OpenGL ES,概述了OpenGL ES 3.0图形管线,讨论了OpenGL ES 3.0的设计理念和限制,最后介绍OpenGL ES 3.0中使用的一些约定和类型。   第2章——你好,三角形:一个OpenGL ES 3.0示例   第2章介绍绘制三角形的一个简单OpenGL ES 3.0示例。我们的目的是说明OpenGL ES 3.0程序的样子,向读者介绍一些API概念,并说明如何构建和运行OpenGL ES 3.0示例程序。   第3章——EGL简介   第3章介绍EGL——为OpenGL ES 3.0创建表面和渲染上下文的API。我们说明与原生窗口系统通信、选择配置和创建EGL渲染上下文及表面的方法,传授足够多的EGL知识,你可以了解到启动OpenGL ES 3.0进行渲染所需的所有知识。   第4章——着色器和程序   着色器对象和程序对象是OpenGL ES 3.0中最基本的对象。第4章介绍创建着色器对象、编译着色器和检查编译错误的方法。这一章还说明如何创建程序对象、将着色器对象连接到程序对象以及链接最终程序对象的方法。我们讨论如何查询程序对象的信息以及加载统一变量(uniform)的方法。此外,你将学习有关源着色器和程序二进制代码之间的差别以及它们的使用方法。   第5章——OpenGL ES着色语言   第5章介绍编写着色器所需的着色语言的基础知识。这些着色语言基础知识包括变量和类型、构造器、结构、数组、统一变量、统一变量块(uniform block)和输入/输出变量。该章还描述着色语言的某些更细微的部分,例如精度限定符和不变性。   第6章——顶点属性、顶点数组和缓冲区对象   从第6章开始(到第11章为止),我们将详细介绍管线,教授设置和编程图形管线各个部分的方法。这一旅程从介绍几何形状输入图形管线的方法开始,包含了对顶点属性、顶点数组和缓冲区对象的讨论。   第7章——图元装配和光栅化   在前一章讨论几何形状输入图形管线的方法之后,第7章将讨论几何形状如何装配成图元,介绍OpenGL ES 3.0中所有可用的图元类型,包括点精灵、直线、三角形、三角形条带和三角扇形。此外,我们还说明了在顶点上进行坐标变换的方法,并简单介绍OpenGL ES 3.0管线的光栅化阶段。   第8章——顶点着色器   我们所介绍的管线的下一部分是顶点着色器。第8章概述了顶点着色器如何融入管线以及OpenGL ES 着色语言中可用于顶点着色器的特殊变量,介绍了多个顶点着色器的示例,包括逐像素照明和蒙皮(skinning)。我们还给出了用顶点着色器实现OpenGL ES 1.0(和1.1)固定功能管线的示例。   第9章——纹理   第9章开始介绍片段着色器,描述OpenGL ES 3.0中所有可用的纹理功能。该章提供了创建纹理、加载纹理数据以及纹理渲染的细节,描述了纹理包装模式、纹理过滤、纹理格式、压缩纹理、采样器对象、不可变纹理、像素解包缓冲区对象和Mip贴图。该章介绍OpenGL ES 3.0支持的所有纹理类型:2D纹理、立方图、2D纹理数组和3D纹理。   第10章——片段着色器   第9章的重点是如何在片段着色器中使用纹理,第10章介绍编写片段着色器所需知道的其他知识。该章概述了片段着色器和所有可用的特殊内建变量,还演示了用片段着色器实现OpenGL ES 1.1中所有固定功能技术的方法。多重纹理、雾化、Alpha测试和用户裁剪平面的例子都使用片段着色器实现。   第11章——片段操作   第11章讨论可以适用于整个帧缓冲区或者在OpenGL ES 3.0片段管线中执行片段着色器后适用于单个片段的操作。这些操作包括剪裁测试、模板测试、深度测试、多重采样、混合和抖动。本章介绍OpenGL ES 3.0图形管线的最后阶段。   第12章——帧缓冲区对象   第12章讨论使用帧缓冲区对象渲染屏幕外表面。帧缓冲区对象有多种用法,最常见的是渲染到一个纹理。本章提供API帧缓冲区对象部分的完整概述。理解帧缓冲区对象对于实现许多高级特效(如反射、阴影贴图和后处理)至关重要。   第13章——同步对象和栅栏   第13章概述同步对象和栅栏,它们是在OpenGL ES 3.0主机应用和GPU执行中同步的有效图元。我们讨论同步对象和栅栏的使用方法,并以一个示例作为结束。   第14章——OpenGL ES 3.0高级编程   第14章是核心章节,将本书介绍的许多主题串联在一起。我们已经选择了高级渲染技术的一个样本,并展示了实现这些功能的示例。该章包含使用法线贴图的逐像素照明、环境贴图、粒子系统、图像后处理、程序纹理、阴影贴图、地形渲染
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值