用于传递API中的依赖关系的技术相关申请的交叉引用
本申请要求于2015年9月13日递交的62/051,183号美国临时专利申
请的权益,其全部内容通过引用并入本文。
背景技术
计算系统已经对现代设备的进步做出了显著贡献,并且被以多个应用
来利用以获得有有益的结果。诸如台式个人计算机(PC)、膝上型PC、平
板PC、上网本、智能电话、服务器等之类的诸多设备辅助了增加的生产力,
并且降低了在娱乐、教育、商业和科学大多数领域中传送和分析数据的成
本。计算系统的一个通用的方面是应用编程接口(API),其是定义不依赖
于各自实施方式的功能的例程、协议和工具的集合,用于构建应用、在应
用之间通信、和/或用于访问计算系统的硬件资源。
在常规API中,应用捆绑/附加像纹理和渲染目标对上下文的资源。驱
动程序追踪所有附属物(attachment)以理解依赖关系并根据需要插入等待
其(WFI)、缓存失效等等。追踪这些附属物的成本是系统中主中央处理
单元(CPU)瓶颈之一。在最近的API中,希望消除资源的捆绑。在无捆
绑的(bindless)API中,当对象的使用改变时,如从对纹理进行渲染转换
为从其进行纹理化,应用指定对象上的“资源转变”。这提供与旧API中
的捆绑相同的信息,除了作为分开的/明确的命令,而不是隐含为捆绑的副
作用。虽然笨拙,但是该方法对于同步和缓存控制是有效的,只是缺少分
块信息等等。对于有时必须对成百上千的对象应用转变以指定单个“依赖
关系”的应用来说,该方法也是笨拙的。工作规范的发生故障性质对工作
提交(经由命令缓冲记录/播放)进一步使常规无捆绑系统复杂。因此,存
在对于改进的无捆绑API的持续需要。
发明内容
本技术可通过参照以下的描述和附图来被最好地理解,附图被用于阐
释涉及用于传递API中的依赖关系的技术的本技术的实施例。
在一个实施例中,技术包括针对所接收的命令识别多个通道。所接收
的命令可以包括用于由图形处理单元(GPU)的一个或多个执行引擎所执
行的渲染命令。针对每组通道,其中该组的第一通道是目的地通道并且该
组的第二通道是源通道,确定目的地通道和源通道的命令之间的一个或多
个依赖关系。所确定的依赖关系可以是一个或多个依赖关系类型,包括执
行依赖关系、缓存依赖关系、分块依赖关系等等。随后针对每个所识别的
通道创建通道对象。每个通道对象记录命令以及相对应的目的地通道和源
通道之间的依赖关系。其后,提交多个通道对象的命令用于根据相对应的
通道对象执行。
该发明内容被提供,以通过简单的方式来介绍一部分概念,将在下面
的具体实施方式中进一步描述该概念。该发明内容并不意欲标识所要求权
利保护的主题内容的关键特征或必要特征,也不意欲被用来限制所要求权
利保护的主题内容的范围。
附图说明
本技术的实施例通过附图中的示例来进行阐释,而非进行限制,其中,
相似的参考标号指类似的元件,并且其中:
图1示出了用于实现本技术的实施例的示例性计算设备的框图。
图2示出了根据本技术的实施例的、传递应用编程接口(API)中的依
赖关系的方法的流程图。
具体实施方式
现将详细参照本技术的实施例,其示例以附图示出。虽然将结合这些
实施例来描述本技术,但是,将理解,其并不意欲将发明限制于这些实施
例。相反地,发明意欲覆盖替换例、修改例和等同例,其可包括在由所附
权利要求所限定的本发明的范围内。另外,在下面的对本技术的详细描述
中,将给出大量的具体细节以提供对本技术透彻的理解。然而,应理解,
本技术可以在没有这些具体细节的情况下得以实施。在其他实例中,未详
细描述公知方法、流程、组件和电路特征以避免不必要地模糊本技术。
之后的本技术的一些实施例以一个或多个电子设备内的例程、模块、
逻辑块、以及对数据的操作的符号化表示的形式来呈现。描述和表现是本
领域技术人员用来最有效地将其工作的实质传达给本领域其他技术人员的
手段。例程、模块、逻辑块和/或等在本文中一般被看作是导致所希望的结
果的自相一致的处理序列或指令。处理是包括对物理量的物理操纵的处理。
通常,虽然不是必要的,这些物理操纵采用电信号或磁信号的形式,该电
信号或磁信号能够被在电子设备中存储、转移、比较和操纵。为了方便,
并参照通用用途,参照本技术的实施例,这些信号被称为数据、比特、值、
元素、符号、字符、术语、数字、串,和/或等等。
但是,应当牢记于心的是,所有这些术语将被解释为参照物理操纵和
数量,并且仅仅是方便的标签,并且将要被进一步以现有技术中通用的术
语来解释。除非特别指出,否则从以下的讨论中可显而易见的,应理解,
通过对本技术的讨论,利用诸如“接收”和/或等等之类的术语的讨论指诸
如操纵和转换数据的电子计算设备之类的电子设备的动作和处理。数据被
表示为电子设备的逻辑电路、寄存器、存储器和/或等等内的物理(例如,
电子的)量,并且被转换成类似地表示为电子设备中的物理量的其他数据。
在本申请中,使用分隔(disjunctive)意欲包括连接(conjunctive)。
定冠词和不定冠词的使用并不意欲指示基数(cardinality)。具体地,对“该”
物体或“一”物体的参照还意欲表示可能多个这种物体中的一个。还要理
解,此处所使用的措辞和术语是出于描述目的的,并且不应当被看作为限
制。
参照图1,示出了用于实现本技术的实施例的示例性计算设备。计算
设备100可以是个人计算机、膝上型计算机、平板电脑、智能电话、游戏
控制台、服务器计算机、客户端计算机、分布式计算机系统等等。计算设
备100包括一个或多个中央处理单元(CPU)110、诸如图形处理单元(GPU)
115的一个或多个专用处理单元、一个或多个计算设备可读介质120、125、
130、以及一个或多个输入/输出(I/O)设备135、140、145、150。I/O设
备135、140、145、150可以包括网络适配器(例如以太网卡)、CD驱动、
DVD驱动和/或等等、以及诸如键盘、点击设备、扬声器、打印机和/或等
等的外围设备。
计算设备可读介质120、125、130可以表现为主存储器和辅助存储器。
一般地,诸如磁存储和/或光存储的辅助存储器提供用于由计算设备100使
用的计算机可读指令和数据的非易失性存储。例如,磁盘驱动程序125可
以存储操作系统(OS)155和应用和数据160。诸如系统存储器120和/或
图形存储器130的主存储器提供用于由计算设备100使用的计算机可读指
令和数据的易失性存储。例如,系统存储器120可以暂时存储当前由CPU
110、GPU115等等使用的操作系统155’的一部分以及一个或多个应用和相
关联的数据160’的一部分。
计算设备可读介质120、125、130、I/O设备135、140、145、150以
及GPU115可以通过芯片集165和一个或多个总线可通信地耦连到处理器
110。芯片集165充当单个输入/输出集线器,用于在处理器110和计算设
备可读介质120、125、130、I/O设备135、140、145、150以及GPU115
之间传达数据和指令。在一个实施方式中,芯片集165包括北桥170和南
桥175。北桥170与处理器110的通信和与系统存储器115的交互。南桥
175提供输入/输出功能。
运行在计算设备100的硬件上的软件的操作的公共方面是应用编程接
口(API)。在命令的执行期间,存在控制应用的适当执行的大量的依赖关
系。API需要提供机制来传递关于用于命令的执行的依赖关系的信息。
现在参考图2,示出了根据本技术的实施例的、传递应用编程接口
(API)中的依赖关系的方法。方法可实现为计算设备可执行指令(例如,
计算机程序),其存储在计算设备可读介质(例如,计算机存储器)中并
由计算设备(例如,处理器)执行。
方法开始于在210处接收执行命令。在一个实施方式中,执行命令包
括用于由一个或多个图形处理单元或中央处理单元的一个或多个执行单元
执行的渲染命令。在220处,针对所接收的执行命令识别多个通道。在230
处,针对每组通道,其中一个通道是目的地通道,另一个通道是相对于彼
此的源通道,确定给定目的地通道和其单独的源通道之间的一个或多个依
赖关系类型的一个或多个依赖关系。依赖关系类型可以包括执行依赖关系、
缓存依赖关系、分块依赖关系等等。在240处,针对所识别的通道创建通
道对象。通道对象记录执行命令以及相对应的给定通道和其单独源通道之
间的依赖关系。可以通过源掩码(mask)、目的地掩码、清除(flush)掩
码、无效掩码等来指定依赖关系。在250处,提交用于通道对象的渲染命
令用于根据相对应的通道对象执行。
通道包括渲染目标的状态,其包括结果将被写入到的图像存储器以及
生成图像内容的渲染命令。通道之间的依赖关系是API如何表达在为依赖
关系目的地的通道中的工作开始之前需要在源依赖关系中完成什么。
在一个示例中,第一通道(源)可以是将纹理渲染到其渲染目标,而
第二通道(目的地)是从其写的源通道的渲染目标的纹理到其自身的渲染
目标在片段着色器中纹理化。因此,依赖关系将指定在目的地通道开始其
片段着色之前源通道需要完成所有其渲染目标写。此外,在一个或多个清
除掩码中所包含的实施方式中,依赖关系指定如果在源通道中使用回写则
数据需要被清除到存储器。类似地,在一个或多个无效掩码中所包含的实
施方式中,依赖关系指定如果在目的地通道中使用一个或多个缓存用于读
则缓存需要被无效。
渲染通道可以对例如1000x1000像素的图像数据进行操作。例如,数
据可被分为比如100x100像素的小块。在这种情况下,希望针对给定块将
绘制命令分组到命令缓冲区中,这样数据可本地于处理引擎而被缓存,以
针对各自的源和目的地通道减少或消除对存储器的读和/或写。如果依赖关
系的性质是第二通道中的每个像素仅依赖于第一通道中的对应像素,则两
个通道之间的边缘被认为是分块边界并且两个通道被认为是可分块的。因
此,可以发出相关命令并以每块的顺序执行,并且通道之间的依赖关系指
示它们是可分块的。
基于上述方法,可以将依赖关系信息分类为三个概念:执行依赖关系、
缓存依赖关系以及分块依赖关系。这些依赖关系概念均不要求每资源状态
追踪。通道对象和依赖关系可被观念化为有向无环图。通道对象和依赖关
系形成偏序,这样命令的集合必须按照有序序列实施。同时,无关的通道
可以在其他通道之间的依赖关系被处理时有利地继续执行。
根据本技术的实施例,渲染通道封装在通道对象中。通道对象指定它
们对其他通道的依赖关系,并且部分指定依赖关系是指定对依赖通道的执
行和缓存依赖关系。在一个实施方式中,执行和缓存依赖关系使用
glMemoryBarrier命令的新的扩展,包括更加整体性的缓存模型。通道对象
还充当收集关于与先前通道的分块缓存交互的信息的场所,特别是使能多
个通道分块缓存以及计算工作和图形的混合的分块缓存。
本技术的实施例与较早的API如开放图形语言(OpenGL)之间的主
要设计区别在于本文本技术的实施例随后称为RAD要求更明确的应用危
害控制和渲染通道之间的依赖关系。API的主要目标是提供在没有CPU/驱
动程序介入的情况下直接针对GPU的状态和捆绑的改变,不再有带有资源
如何被使用以及该使用何时改变的知识的中央仲裁器,所以RAD必须依赖
于以某种形式提供该信息的应用。特别地,必须替换的主要功能包括:
—执行依赖关系:理解在随后工作可开始之前必须完成什么工作;
—缓冲清除和无效:当对资源写入新数据时确保非一致(non-coherent)
缓存被清除或无效;
—解压缩:如果经压缩的表面将被不支持压缩的硬件单元访问,则将
经压缩的表面分解为未压缩的;
—分块:以允许一个或多个通道被每块回放从而优化芯片外存储器带
宽的方式表达渲染通道之间的依赖关系。
这四个功能常在渲染算法期间被同时需要并且要求类似的信息,所以
在用于将该信息提供给驱动程序的操作中存在重大的重叠。
考虑简单的示例——对纹理进行渲染并且随后在片段着色器中从其进
行纹理化。执行依赖关系是第一通道中的渲染目标写必须在开启未来片段
工作之前完成。如果渲染目标写是回写缓存,那么缓存必须被清除,并且
如果来自渲染目标的数据先前已经缓存到纹理缓存中,则缓存必须被无效。
如果纹理单元不支持访问给经压缩的渲染目标,其必须被解压缩。最后,
驱动程序需要知道第二渲染通道是否可以随第一通道被每块执行,其取决
于渲染目标的哪些纹理像素(texel)被第二通道的哪些像素所读。
对于这四个功能,解压缩在具体的对象上操作,所以对它的处理和对
其余几个功能的处理不同。当创建纹理时,应用指定将采用何种访问类型
经由(早先记录的)radTextureAccess命令来使用它。这允许如果任何访问
类型将得益于压缩则驱动程序采用压缩资源分配内存。应用还可通过采用
<enable>=RAD_TRUE在存储被分配之前调用如下命令来选择加入到对解
压缩的明确控制:
voidradTextureCompressionControl(RADtexturetexture,RADbooleanenable);
在存储被分配之后,应用可以随后查询当由具体访问使用时纹理的格
式和类型是否需要人工解压缩。如果纹理使压缩控制使能,那么应用负责
使用如下命令根据需要解压缩内存:
voidradDecompressTexture(RADtexturetexture,RADuintlevel,
RADuintxoffset,RADuintyoffset,RADuintzoffset,
RADsizeiwidth,RADsizeiheight,RADsizeidepth);
如果纹理使压缩控制禁用,则每次其释放为渲染目标时驱动程序自动
解压缩内存。(注意:这假设渲染是内存变得压缩的主要方式。如果不是
这种情况,驱动程序可要求人工明确解压缩控制以针对纹理分配压缩)。
在定义缓存无效接口之前,具有定义缓存层级的心智模型是很重要
的,针对缓存层级可评估任何接口。
—每个访问类型可具有非一致的、可能分布式的L1缓存(分布以更靠
近着色器或其他处理引擎)。如果访问类型是只读的(纹理、一致缓冲区),
则缓存可被回写或透写(writethrough)。在一些实施方式中,多个访问类
型可以共享单个缓存。给定对处理器的位置,L1缓存可以仅通过产生缓存
条目的队列是可无效的。
—所有GPU访问可以共享一致L2缓存。该缓存如果存在则必须在所
有GPU访问之间是一致的,但是在CPU和GPU之间不需要是一致的。“一
致”在该情况下意思是来自对GPU的任何单元的任何GPU访问的写将被
来自对GPU的任何单元的任何其他GPU访问所看到,假定写已到L2缓存
并且读未命中旧的(stale)L1缓存条目。如果实施方式没有L2缓存,则
GPU存储器必须具有该相同一致的行为。L2缓存可以被回写或透写。
—FenceSync命令使任何回写L1缓存与其被提交以在其发信号完成之
前通过一致L2被写的队列相关。
存在几个种类的存储器“客户端”,所有读和写存储器以及下面的缓
存无效规则对要求何种操作来使这些写和读有效地彼此一致进行定义。客
户端包括CPU、GPU复制命令集、经由GPU处理的GPU访问集(所有访
问类型)。
在命令提交到队列之前发生的CPU写将自动对该队列上的那些随后
的命令可见,没有由应用提供的附加信息。该需求的一个可行的驱动程序
实施方式是每次一批工作提交(或“清除”)到队列时使所有L1缓存和
L2缓存的任何CPU可访问行无效。虽然这听起来严厉,但是清除通常不
很频繁,并且CPU可访问行所使用的缓存的部分通常较小。
针对CPU读去看GPU写的结果,不管经由复制命令还是GPU处理,
那些写必须被清除出任何回写L1或L2缓存,并且随后CPU必须等待写完
成。这可通过使用FenceSync命令中的合适标志来完成。
如果对相同存储器的CPU和GPU写均没有充分同步执行和缓存清除,
则上述规则不适用并且结果未定义。
GPU复制命令意为“流”操作并且因此不使用持久L1缓存。它们更
一般地具有单行缓冲以合并使用之后立即清除的读和写。特别地,它们的
读将总是访问来自L2的当前数据,并且写将写到L2。同样地,它们不具
有要求无效的其自身的缓存,但是它们的写可以使其他访问类型L1缓存中
的行陈旧。
复制命令以半自动的方式使其他单元L1缓存无效。应用仅负责经由
同步对象表达复制队列和其他队列之间的执行依赖关系,基于这些执行依
赖关系的规则给驱动程序提供使合适的缓存无效所需要的信息。进一步地,
驱动程序知道针对复制的目的地存储器使能何种访问类型,这允许其进一
步限制无效哪些缓存。
基本规则是对于复制队列上的复制命令具有定义好的行为,必须有:
—来自可具有旧缓存值的任何队列的FenceSync(OtherQ)->
QueueWaitSync(CopyQ)依赖关系,其中FenceSync是存储器的最后读/写之
后并且QueueWaitSync是在复制之前。以及
—在复制之后并且在其他队列上存储器的任何后续读/写之前的
FenceSync(CopyQ)->QueueWaitSync(OtherQ)依赖关系。
该半自动的缓存无效行为存在多种可能的实施方式。首先,如果复制
队列能够无效其他队列L1缓存,则它可立即这么做或在下一个FenceSync
命令处这么做,轻松满足该需求。
第二可能的实施方式是使用为同步对象的源的队列所提供的信息在
QueueWaitSync时间实施缓存无效。这允许无效遵从可无效其自身缓存的
队列。
如果GPU存储器空闲和重新利用/重新分配,则驱动程序负责担保在
存储器被重新分配之前针对该存储器没有旧的缓存行。
剩余的客户端是通过使用GPU处理的任何访问类型的读和写。当存在
依赖关系时,使用“屏障(barrier)”清除和无效这些缓存是应用的责任。
用于屏障的具体的API在下面的章节加以描述,但是从概念上讲屏障具有
四个状态:
—srcMosk,dstMask:管线级的位段
—flushMask,invalidoteMask:访问类型的位段
屏障提供关于执行屏障和缓存清除与无效的信息。<srcMosk>和
<dstMask>指示执行依赖关系的源和目的地,即由<dstMask>所指示的管线
级上的任何工作不可以开始,直到由<srcMosk>所指示的管线级上的先前
工作已经完成。<flushMask>和<invalidateMask>分别指示哪些访问类型缓存
需要被写回(清除到L2)或无效(丢弃)。缓存清除和/或无效发生在由
<srcMosk>所指示的工作完成之后并在由<dstMask>所指示的工作开始之
前。
回到我们较早的简单的渲染-到-纹理的示例,操作将负责在渲染和纹
理通道之间插入屏障,采用如下参数:
srcMask=RAD_RENDERTARGET_STAGE_BIT
dstMask=RAD_FRAGMENT_STAGE_BIT
flushMask=RAD_RENDERTARGET_ACCESS_BIT
invalidateMask=RAD_TEXTURE_ACCESS_BIT
渲染算法一般包括一组“通道”,其中每个通道生成一个渲染目标作
为输出(或共同生成的多个渲染目标、aka"MRT")。使用简单的渲染-到-
纹理示例,对纹理的渲染是第一通道,并且在从纹理进行纹理化的同时对
第二渲染目标的渲染是第二通道。
这些通道之间的真实的依赖关系形成有向无环图(DAG),但是常规
的图形API仅表达线性命令序列,有效地表示“平面(flattened)”形式的
DAG。那些API还依赖于严厉的命令顺序以担保在后续通道开始之前完成
依赖通道。在现代API如驱动程序不检查捆绑信息的RAD中,驱动程序不
能反向设计真实的依赖关系,并且因此对于应用来说明确提供该信息是重
要的。
“通道”对象表示DAG中的节点,并且包括表示DAG中的边缘的依
赖关系信息。通道包括关于输入(依赖关系、屏障、保存的缓冲区)、输
出(渲染目标、丢弃的缓冲区、分解的缓冲区)以及分块状态(1:1像素映
射、滤波带宽、内存印记)的信息。分块状态为实施方式提供足够的信息
以支持多通道分块,即在移动到渲染目标中的下一个块之前渲染一个以上
的通道。
更详尽地,状态包括:
—渲染目标附属物:颜色、深度和通道的结果写入到的模板缓冲区。
初始状态没有附属物。
voidradPassRenderTargets(RADpasspass,RADuintnumColors,
canstRADrenderTargetHandle*colors.
RADrenderTargetHandledepth,
RADrenderTargetHandlestencil);
—保存的缓冲区:颜色、深度和模板附属物的缓冲区在通道的开始保
存它们的内容。如果附属物的内容没有保存,则依赖于那些内容产生未定
义的行为。初始状态是所有附属物被保存。
voidradPassPreserve(RADpasspass,RADattachmentattachment,
RADbooleanenable);
—丢弃的缓冲区:其纹理使它们的内容在通道最后被丢弃。该命令采
用纹理CPU处理而不是附属物枚举,因为需要丢弃的缓冲区可能为在先前
通道中并且不在当前通道中的渲染目标。该命令还接受应用于每个丢弃的
“像素偏移”,其在多通道分块的上下文中稍后描述。初始状态是没有纹
理被丢弃。
voidradPassDiscard(RADpasspass,RADui.ntnumTextures,
canstRADtexture*textures,
canstRADoffsetZD*offsets);
—分解的缓冲区:其多重采样颜色附属物在通道的最后被分解到非多
重采样颜色缓冲区。如果这样的多重采样缓冲区还被标志为被丢弃,则在
丢弃之前立即发生分解。初始状态为没有附属物被分解。
voidradPassResolve(RADpasspass,RADattachmentattachment,
RADtextureresolved);
—存储的缓冲区:其纹理应使它们的内容在通道的最后被清除到存储
器。“存储”是纹理应被从分块存储器中清除到芯片外存储器的提示,因
此多通道分块序列的剩余部分不需要其内容。不对将被存储的纹理做标记
并不意味着其是被丢弃的,内容将被保存,但是不在合适的时间存储缓冲
区可将它保持在分块存储器中比所需要的更长的时间。存储还涉及像素偏
移,理由类似于丢弃。初始状态为没有纹理被存储。
voidradPassStore(RADpasspass,RADuintnumTextures,
canstRADtexture*textures,
canstRADoffset2D*offsets);
—裁剪矩形:对通道中所有操作充当剪刀的渲染目标的二维区域,包
括渲染、丢弃和分解。初始状态为未裁剪,即(x,y)=(0,0),(宽度,高度)
=(max,max)。
voidradPassClip(RADpasspass,RADuintx,RADuinty,
RADuintwidth,RADuintheight);
—依赖通道:该通道依赖的通道列表。实施方式必须担保那些通道已
经完成到屏障所描述的级别。初始状态是没有依赖关系。
voidradPassDependencies(RADpasspass,RADuintnumPasses,
canstRADpass*otherPasses);
—屏障:先前通道和当前通道之间的依赖关系中所涉及的缓存和级的
描述。如在屏障章节所描述的,在当前通道中的工作可开始直到<dstMask>
之前,在依赖通道中的工作直到<srcMask>必须完成,并且根据<flushMask>
被从缓存中清除和根据<invalidateMask>被无效。初始状态是没有屏障。
voidradPassBarrier(RADpasspass,RADbitfieldsrcMask,RADbitfield
dstMask,
RADbitfieldflushMask,RADbitfieldinvalidateMask);
—分块边界:指示是否安全以每块随其依赖关系执行该通道的布尔运
算(boolean)。如果是真(指示这是边界),则分块器必须在开始该通道
之前被清除。如果当前通道中的片段线程之间存在屏幕空间关联并且先前
渲染目标的纹理像素被那些片段线程所获取,则应用可以将其设置为假。
通常其必须为1:1映射,但是API也考虑到非零“滤波带宽”。初始状态
为边界=真(TRUE)。
voidradPassTilingBoundary(RADpasspass,RADbooleanboundary);
—分块滤波带宽:API调节(accommodate)多通道分块,其中第二通
道在源纹理坐标和片段线程窗口坐标之间不具有精确的1:1关系。如果应
用可以担保纹理坐标在窗口坐标+/-[filterWidth,filterHeight]内,其可以使能
跨这种依赖关系的多通道分块(即边界=假(FALSE))。初始状态为
filterWidth=filterHeight=0。
voidradPassTileFilterWidth(RADpasspass,
RADuintfilterWidth,RADuintfilterHeight);
—块印记:对于多通道分块,实施方式可需要预先知道块将使用多少
内存,这样它可以选择最有效的块大小。内存印记取决于每个像素的“工
作集”大小,即每像素的全部字节在多通道期间的任何时间有效(active)。
印记还取决于最大滤波带宽,其影响多少像素必须在任何时间保持有效。
初始状态是bytesPerPixel=maxFilterWidth=0。
voidradPassTileFootprint(RADpasspass,RADuintbytesPerPixel,
RADuintmaxFilterWidth);
每像素的字节可需要通过包括抗锯齿模式可被做得更精确。
采用平常的命令(radCreatePass、radReferencePass、radReleasePass)
来管理通道的寿命,并且通过radCompilePass而使其不可变。编译通道不
涉及将其与渲染命令相关联,这意味着通道可随后被使用以提交渲染命令。
在钻研通道行为之前,理解分块硬件的模型以及它们如何与多个通道
交互很重要。分块器行为主要存在两类:
(1)明确管理的块内存。这类硬件明确要求在每个通道的开始芯片外
存储器加载到芯片上块内存中,并且相反地,在每个通道的结束将块内存
存储到芯片外存储器。除一些简单情况如多重采样分解之外,明确管理的
硬件通常不服从多通道分块并且可有效地在每通道之间插入边界。多通道
分块将要求由渲染目标以潜在复杂的方式对块内存进行分区,并要求是纹
理请求能够锁定快内存的部分。如果应用要求多通道分块,其很可能回落
到单个通道。
(2)基于一致缓存的块内存。该类硬件具有充当缓存的块内存,一经
要求则从存储器加载行,并根据需要驱逐到存储器。进一步地,该缓存还
为其他存储器访问类型如纹理服务,所以可能从块内存高效地纹理。这可
以是与早先描述的相同的LZ缓存。这种类型的硬件较多地服从于多通道分
块并且是多通道设计的主要目标。
一些通道状态取决于分块硬件的类型而具有不同的内部行为:
—“保存”:在明确管理的硬件上,这要求从芯片外存储器到块内存
的加载/复制。在基于缓存的硬件上,这可能是nap。
—“丢弃”:在明确管理的硬件上,丢弃的缓冲区意味着跳过从块内
存到芯片外存储器的存储/复制。在基于缓存的硬件上,这可使缓存行无效
而不清除到芯片外存储器的暗行(dirtyline)。当附属物未被丢弃时,明确
管理的硬件将在通道的结束存储/复制内存,而基于缓存的硬件可什么也不
做。基于缓存的硬件还可以在多通道序列的随后通道期间丢弃内存/使内存
无效。
—“存储”:在明确管理的硬件上,这可能是nap,因为已经由于先前
通道而在芯片外存储器中,或将在当前通道的结束复制到存储器。在基于
缓存的硬件上,这可清除回写缓存存储器的一部分。
—“裁剪矩形”:在明确管理的硬件上,该矩形定义加载和存储应用
到的区域。在基于缓存的硬件上,这可能仅充当用于渲染命令的剪刀。
—“块印记”:在明确管理的硬件上,其可被忽略并且块大小单独地
基于渲染目标而选择。在基于缓存的硬件上,该印记可以用于针对多通道
序列计算所希望的块大小。
在基于缓存的硬件上,多通道分块相当直截了当地假定从早先的通道
读取的像素纹理坐标与当前通道中的片段坐标之间存在的精确的1:1映射。
其可以由应用通过设置boundary==FALSE和filterWidth/Height==0来指示。
当是这种情况时,实施方式可以选择块大小,多通道中的整个通道工作集
可以通过使用块印记状态的bytesPerPixel而适合缓存存储器。实施方式必
须仍在每块的基础上遵守屏障状态,但是所有相关通道的块可以适合缓存
存储器,并且丢弃和存储命令可以如常操作。
当像素纹理坐标与窗口位置的映射不是精确的1:1时,虽然较为复杂,
但是多通道分块仍是可能的。当应用可以担保像素纹理坐标在经由
radPassTileFilterWidth命令所指定的窗口坐标的预定“filterWidth”内时,
RAD支持这样的多通道分块。该实施方式可以使用其来通过朝着原点的
(filterWidth,filterHeight)像素调节通道之间的分块矩形,这样来自先前通道
的有效内容的边界围绕块的两个远边缘是可用的。类似地,应用负责针对
丢弃和存储命令提供精确的像素偏移。这些命令也朝着原点偏移,并且通
过对filterWidth加倍来偏移它们,有效区域维持在块的两个近边缘周围。
围绕当前和最近块的有效存储器的这些外部条带(strip)是为什么应
用应该努力提供精确的maxFilterWidth的原因,因为实施方式将尝试保留
缓存空间以在缓存中保持该存储器。
不像计算命令可与图形命令自由交叉并且那些命令被明确排序的其他
API,RADAPI要求计算命令在分开的专用计算通道中(或以其他计算队
列异步运行)当纹理坐标和计算着色器调用ID之间存在关系时,计算通道
还可以随渲染通道而被分块。计算通道可以指定该关系的性质,其可以是
每计算调用一个像素或没计算调用个NxM像素。如果计算调用自然地适
合针对渲染所选择的块形状,则跨这种通道的分块是可能的。应用可以使
用命令radPassTileComputeFootprint来指定像素中的计算工作组的形状。
除了指定经由多个通道的依赖关系以外,使用命令定义通道内的依赖
关系也是可能的:
radQueuePassBarrier(RADqueuequeue,RADbitfieldsrcMask,
RADbitfielddstMask,
RADbitfieldflushMask,RADbitfieldinvalidateMask);
这可被看作将当前节点分为两个节点,第二节点根据所指定的屏障依
赖于第一节点。这可在存储器屏障(MemoryBarrier)或纹理屏障
(TextureBarrier)在OpenGL中有用的情形下是有用的。
使用如下命令将针对通道的工作提交到队列:
voidradQueueBeginPass(RADqueuequeue,RADpasspass);
//在开始/结束之间将工作提交到队列
voidradQueueEndPass(RADqueuequeue);
在通道期间提交复制或FenceSync命令或在图形通道期间提交计算匹
配命令是非法的。这些命令必须在通道之外发生(在这种情况下它们将被
假定依赖于在它们之前所提交的所有通道),或者复制和计算命令可被提
交到不同的(异步)队列。
如何使用通道的一些示例:
单个通道、没有依赖性、在最后丢弃深度:
poss0=radCreatePass(device);
//设置颜色和深度缓冲区
radPassRendertargets(pass0,1,&color0,depth,0);
//深度缓冲区在最后被丢弃,没有偏移
radPassDiscard(pass0,depthCPUhandle,/*offset*/{0,0});
//完成通道对象
radCompilePass(pass0);
//使用通道
radQueueBeginPass(queue,pass0);
//提交工作
radQueueEndPass(queue);
单个通道、下采样、然后丢弃:
pass0=radCreatePass(device);
//设置多重采样颜色缓冲区
radPassRendertargets(pass0,1,&colorMS,0,0);
//多重采样缓冲区的先前内容将不被保存
radPassPreserve(pass0,colorattachment0,RAD_FALSE);
//多重采样数据将在通道的最后被丢弃
radPassDiscard(pass0,colorMS,l*offset*/{0,0});
//多重采样数据将在其被丢弃之前被分解为colorlX
radPassResolve(pass0,colorattachment0,colorlX);
radCompilePass(pass0);
radQueueBeginPass(queue,pass0);
//提交工作
radQueueEndPass(queue);
对两个纹理进行渲染,然后以1:1的纹理像素:像素映射使用它们:
//通道0对纹理之一(color0)的渲染
pass0=radCreatePass(device);
radPassRendertargets(pass0,1,&color0,0,0);
radPassTileFootprint(pass0,12bytesperpixel,0pixelmaxfilterwidth);
radCompilePass(pass0);
//将工作提交到通道0,针对通道1重复
pass2=radCreatePass(device);
radPassRendertargets(pass2,1,&color2,0,0);
radPassTileFootprint(pass2,12bytesperpixel,0pixelfilterwidth);
//通道2依赖于通道0和通道1
radPassDependencies(pass2,2,{pass0,passl});
//允许采用通道0和通道1进行多通道分块
radPassTilingBoundary(FALSE);
//当前通道不能开启片段工作,直到早先的渲染目标写完成
radPassBarrier(pass2,
/*srcMask*IRAD_RENDERTARGET_STAGE_BIT,
/*dstMask*IRAD_FRAGMENT_STAGE_BIT,
/*flushMask*IRAD_RENDERTARGET_ACCESS_BIT,
/*invalidateMask*IRAD_TEXTURE_ACCESS_BIT);
//在该通道的最后丢弃暂时的color011
radPassDiscard(pass2,color0,0);
radPassDiscard(pass2,colorl,0);
radCompilePass(pass2);
带有偏移和丢弃的复杂多通道:
pass0=radCreatePass(device);
radPassRendertargets(pass0,1,&color0,0,0);
//每像素8字节(color0中4个,colorl中4个)
radPassTileFootprint(pass0,8bytesperpixel,2pixelmaxfilterwidth);
radCompilePass(pass0);
//将工作提交到通道0
passl=radCreatePass(device);
radPassRendertargets(passl,1,&colorl,0,0);
radPassTileFootprint(passl,8bytesperpixel,2pixelfilterwidth);
//纹理坐标在窗口位置的+I-2x2像素内
radPassTileFilterWidth(passl,{2,2}pixels);
//跨进入的依赖关系(通道0)的块
radPassTilingBoundary(FALSE);
radPassDependencies(passl,1,&pass0);
//当前通道不能开启片段工作,直到早先的渲染目标写完成
radPassBarrier(passl,
l*srcMask*IRAD_RENDERTARGET_STAGE_BIT,
l*dstMask*IRAD_FRAGMENT_STAGE_BIT,
l*flushMask*IRAD_RENDERTARGET_ACCESS_BIT,
l*invalidateMask*IRAD_TEXTURE_ACCESS_BIT);
//在该通道的最后丢弃暂时的color0,带有双倍的滤波宽度的偏移
radPassDiscard(passl,color0,4pixels);
//在该通道的最后存储colorl
radPassStore(passl,colorl,0pixels);
radCompilePass(passl);
本技术的实施例有利地指定用于同步、缓存控制、存储器分块使用情
况等等的依赖关系。本技术的实施例不仅更为简单,而且针对驱动程序和
应用更高效地实现和使用。
出于阐释和描述目的,已经呈现了以上对本技术的具体实施例的前述
描述。其并不意欲是穷尽式的,或将发明限制到所公开的精确形式,并且,
显而易见地,鉴于以上教导,许多修改例和变换例可使能的。实施例被选
择并描述,以便最好地说明本技术的原理及其实际应用,从而使得本领域
其他技术人员能够最佳地利用本技术和带有适于所构想的特定用途的各种
修改例的各种实施例。意欲使发明的范围由此处所附的权利要求及其等同
物所定义。