《OpenGL编程指南(原书第8版)》(4)

因为需要把声明为shared的变量存储到图形处理器的高性能资源环境中,而这样的资源环境是有限的,所以需要查询和了解某个计算着色器程序的共享变量的最大数量。要获取这个限制值,可以调用glGetIntegerv()并设置pname为GL_MAX_COMPUTE_SHARED_MEMORY_SIZE。

同步

如果本地工作组请求的执行顺序,以及全局工作组中的所有本地工作组的执行顺序都没有定义,那么请求执行操作的时机与其他请求就是完全无关的。如果请求之间不需要互相通信,只需完全独立地执行,那么这样并没有什么问题。但是,如果请求之间需要进行通信,无论是通过图像,缓存还是共享内存,那么我们就有必要对它们的操作进行同步处理了。

同步命令的类型有两种。首先是运行屏障(execution barrier),可以通过barrier()函数触发。它与细分控制着色器中的barrier()函数类似,后者可以用来实现控制点处理过程中的请求同步。如果计算着色器的一个请求遇到了barrier(),那么它会停止运行,并等待同一个本地工作组的所有请求到达为止。当请求从barrier()中断的地方重新开始运行的时候,我们可以断定其它所有的请求也已经到达了barrier(),并且在此之前的所有操作均已经完成。barrier()函数在计算着色器中的用法比在细分控制着色器中更为灵活。尤其是,不需要限制在着色器中的main()函数中执行barrier()。但是,必须在统一的流控制过程中调用barrier()。也就是说,如果本地工作组的一个请求执行了barrier()函数,那么同一工作组的所有请求都必须执行这个函数。这样是合理的,因为着色器的某个请求不可能知道其它请求的控制流情况,所以只能假设其它请求也能到达屏障的位置,否则将会发生死锁的情形。

如果在本地工作组内进行请求间的通信,那么可以在一个请求中写入共享变量,然后在另一个请求中读取。但是,我们必须确定目标请求中读取共享变量的时机,即在源请求已经完成对应的写入操作之后。为了确保这一点,我们可以在源请求中写入变量,然后在两个请求中同时执行barrier()函数。当目标请求从barrier()返回的时候,源请求必然已经执行了同一个函数(也就是完成共享变量的写入),因此可以安全地读取变量的值了。

第二种类型的同步叫做内存屏障(memory barrier)。内存屏障的最直接的版本就是memoryBarrier()。如果调用memoryBarrier(),那么就可以保证着色器请求内存的写入操作一定是提交到内存端,而不是通过缓冲区(cache)或者调度队列之类的方式。所有发生在memoryBarrier()之后的操作在读取同一处内存的时候,都可以使用这些内存写入的结果,即使是同一个计算着色器的其它请求也是如此。此外,memoryBarrier()还可以给着色器编译器做出指示,让它不要对内存操作重排序,以免因此跨越屏障函数。如果你觉得memoryBarrier()的约束过于严格,那么你的感觉很正确。事实上,memoryBarrier()系列中还有其它不同的内存屏障子函数。memoryBarrier()所做的只是简单地按照某种未定义的顺序(这个说法不一定准确)依次调用这些子函数而已。

memoryBarrierAtomicCounter()函数会等待原子计数器更新,然后继续执行。memoryBarrierBuffer()和memoryBarrierImage()函数会等待缓存和图像变量的写入操作完成。memoryBarrierShared()函数会等待带有shared限定符的变量更新。这些函数可以对不同类型的内存访问提供更为精细的控制和等待方法。举例来说,如果正在使用原子计数器来实现缓存变量的访问,我们可能希望确保原子计数器的更新被通知到着色器的其它请求,但是不需要等待缓存写入操作本身完成,因为后者可能会花费更长的时间。此外,调用memoryBarrierAtomicCounter()允许着色器编译器对缓存变量的访问进行重排序,而不会受到原子计数器操作的逻辑影响。

注意,就算是调用memoryBarrier()或者它的某个子函数,我们依然不能保证所有的请求都到达着色器的同一个位置。为了确保这一点,我们只有调用执行屏障函数barrier(),然后再读取内存数据,而后者应该是在memoryBarrier()之前被写入的。

内存屏障的使用,对于单一着色器请求中内存交换顺序的确立来说并不是必需的。在着色器的某个请求中读取变量的值总是会返回最后一次写入这个变量的结果,无论编译器是否对它们进行重排序操作。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/fdb94dca9221830e0a6b16cf1b3c52b7.html