一次调用可以在 glsl 计算着色器中进行乒乓传播吗?
Posted
技术标签:
【中文标题】一次调用可以在 glsl 计算着色器中进行乒乓传播吗?【英文标题】:Ping pong propagation in glsl compute shader possible in one call? 【发布时间】:2013-09-13 04:18:28 【问题描述】:我尝试使用 glsl 计算着色器实现 32x32x32 3D 纹理的传播方案,如果我可以只执行一次着色器进行 x 次迭代,那就太好了。
我有 3 个纹理,一个是源,一个是目标,第三个是累积一切。每次迭代都必须交换源和目标。 伪代码看起来像 OpenGL:
glUseProgram(computeShaderId);
glBindImageTexture(0, srcTexId, 0, GL_TRUE, 0, GL_READ_WRITE, GL_RGBA32F);
glBindImageTexture(1, targetTexId, 0, GL_TRUE, 0, GL_READ_WRITE, GL_RGBA32F);
glBindImageTexture(2, accumulateTexId, 0, GL_TRUE, 0, GL_READ_WRITE, GL_RGBA32F);
glDispatchCompute(32,32,32);
GLSL:
#version 430
layout (local_size_x = 1, local_size_y = 1, local_size_z =1) in;
layout(rgba32f) uniform image3D srcTex;
layout(rgba32f) uniform image3D targetTex;
layout(rgba32f) uniform image3D accumulateTex;
void main()
ivec3 currentPos = ivec3(gl_GlobalInvocationID.xyz);
for (int i=0;i<8;i++)
//accumulate the values of the 6 neighbours (top,bottom,left,right,front,back)
//by usind the current sourceTexture
//this involes loadImage
vec4 neighbourValues=getValuesFrom6Neighbours(currentPos, currentSource);
storeImage(currentTarget,currentPos,neighbourValues);
vec4 value=loadImage(accumTex,currentPos);
storeImage(accumTex,currentPos,neighbourValues+value);
//the texture are swapped, which I have a solution for so no problem here
swapSrcAndTarget();
//here is the Problem how to synchronize all different shader invocations?
someKindOfBarrier();
问题是由于纹理的大小,我无法在一个工作组中完成所有这些工作。它会在一个工作组中,我可以使用 barrier() 就可以了。 由于纹理的交换,我需要在从下一次迭代再次读取之前更新所有值。 有人知道这是否可能吗?
谢谢 马克
【问题讨论】:
【参考方案1】:正如您所说的那样,所有内容都不适合活动线程,所以我不认为这是直接可能的,除非您接受会有错误(当您读取的一半值可能来自更新之前或之后) .换句话说,所有线程都必须完成第一次 ping,然后才能继续进行 pong。由于一次只物理执行了一部分线程,因此将 pass 放入循环中是行不通的。
我能想到两件事。
-
将问题分解为可以容纳的图块,但在完成内核/调度之前,图块边缘之间将没有通信(邻居可能是陈旧的)。
实现您自己的调度,并使用 atomic opts 尝试获取任务,直到完成完整的 ping 操作(意味着手动同步)。只有在 memoryBarrier() 之后才能继续进行乒乓球比赛。根据经验,这可能比将 glDispatchCompute 放入 for 循环中慢很多。
【讨论】:
是的,我尝试通过使用 atmoic 增量递增变量来手动同步,并尝试等待该变量达到表示完成一次迭代的值(在本例中为 32768)。问题是我没有找到暂停执行的好方法,我尝试了一个while循环,但这几乎立即破坏了图形驱动程序。我认为您是对的,最好的方法是使用一个 glDispatchCompute 进行一次迭代。谢谢 我以前曾在着色器工作中看到过这样的循环:blog.icare3d.org/2010/07/…,但用新的东西让 GLSL 面对它并不需要太多。例如,当我尝试使用“while (!done()) no-op(); then-execute();”它曾经失败,但将代码放入循环中似乎有效:“while (waiting) if(done()) execute(); waiting=false;”。我已经开始查看着色器二进制文件(它会吐出一些类似汇编的文本,至少在 NVIDIA 上)只是为了确保没有发生真正奇怪的事情。祝你好运:)以上是关于一次调用可以在 glsl 计算着色器中进行乒乓传播吗?的主要内容,如果未能解决你的问题,请参考以下文章
满足条件时是不是可以在 GLSL 着色器中回调 C/C++ 函数/代码? [关闭]