将组共享变量读回 cpu 内存
Read groupshared variables back to cpu memory
首先,是否可以读取组共享数据?还是在将组共享数据传输到 cpu 内存之前需要将其复制到某个 RWbuffer?由于 RWbuffers 不能进行组共享(我假设这是因为您在编译时不知道缓冲区的大小)。
对于那些感兴趣的人,这是它在声明组共享缓冲区时抛出的错误:
Shader error in 'FOWComputeShader': 'Result': groupshared variables cannot hold resources at kernel CSMain at ...
基本上我在着色器中声明了一个大的 groupshared uint 数组,价值 16kb。我将主代码中的计算缓冲区链接到这个组共享数组。分派着色器,然后从缓冲区中读回。遗憾的是我读回的数据都是0.
我在一个带有计算着色器的统一环境中工作,像这样设置我的缓冲区:
// MapSize is 128 * 128, so 16kb
// sizeof(uint) is the stride size
// ComputeBufferType.Raw, because I intend to use each uint as 4 bytes later on, so I don't want funny stuff to happen to the values
ComputeBuffer FOWMapBuffer = new ComputeBuffer(MapSize, sizeof(uint), ComputeBufferType.Raw);
FOWComputeShader.SetBuffer(kernel, "_FoWMap", FOWMapBuffer);
//just the dispatch
int ThreadCount = Mathf.CeilToInt((float)FOWdata.Count / ThreadGroupSizeX);
FOWComputeShader.Dispatch(kernel, ThreadCount, 1, 1);
//outVisibleToFaction is a byte array of 128 * 128 size
FOWMapBuffer.GetData(outVisibleToFaction);
FOWMapBuffer.Dispose();
然后在着色器内部:
// 4096 uints * 4 bytes per uint = 16kb
#define FoWMap_Size 4096
groupshared uint _FoWMap[FoWMap_Size];
[numthreads(32,1,1)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
for (uint i = 0; i < FoWMap_Size; i++)
{
_FoWMap[i] = i;
}
}
这就是我的环境。
有谁知道是否可以读回组共享数据,如果可以,那为什么我的缓冲区读回全是 0?
不,您不能直接访问 CPU 上的组共享内存。 Groupshared 内存是一块片上内存,顾名思义,它仅在单个组内的线程之间共享,因此甚至没有一个 groupshared 内存,而是多个实例(可能会也可能不会-存在,取决于硬件和着色器)。一旦它所属的线程组完成执行(这允许硬件为下一个线程组重新使用该内存),每个组共享内存块的生命周期就会结束。例如,在您的情况下,您实际上是在分派 ThreadCount
个组,因此会有那么多 16 kb 组共享内存的逻辑块,每个逻辑块的大小为 16 kb。
因此,总而言之,组共享内存更像是一个临时缓存,您可以使用它让线程组中的线程可以相互通信。除了线程组中的这 32 个线程之外,没有人知道该内存的内容甚至存在(因为它仅在这些线程当前执行时才真正存在)。
如果这 32 个线程之外的任何线程需要访问内存,您需要将其写出到 RW 缓冲区。
首先,是否可以读取组共享数据?还是在将组共享数据传输到 cpu 内存之前需要将其复制到某个 RWbuffer?由于 RWbuffers 不能进行组共享(我假设这是因为您在编译时不知道缓冲区的大小)。
对于那些感兴趣的人,这是它在声明组共享缓冲区时抛出的错误:
Shader error in 'FOWComputeShader': 'Result': groupshared variables cannot hold resources at kernel CSMain at ...
基本上我在着色器中声明了一个大的 groupshared uint 数组,价值 16kb。我将主代码中的计算缓冲区链接到这个组共享数组。分派着色器,然后从缓冲区中读回。遗憾的是我读回的数据都是0.
我在一个带有计算着色器的统一环境中工作,像这样设置我的缓冲区:
// MapSize is 128 * 128, so 16kb
// sizeof(uint) is the stride size
// ComputeBufferType.Raw, because I intend to use each uint as 4 bytes later on, so I don't want funny stuff to happen to the values
ComputeBuffer FOWMapBuffer = new ComputeBuffer(MapSize, sizeof(uint), ComputeBufferType.Raw);
FOWComputeShader.SetBuffer(kernel, "_FoWMap", FOWMapBuffer);
//just the dispatch
int ThreadCount = Mathf.CeilToInt((float)FOWdata.Count / ThreadGroupSizeX);
FOWComputeShader.Dispatch(kernel, ThreadCount, 1, 1);
//outVisibleToFaction is a byte array of 128 * 128 size
FOWMapBuffer.GetData(outVisibleToFaction);
FOWMapBuffer.Dispose();
然后在着色器内部:
// 4096 uints * 4 bytes per uint = 16kb
#define FoWMap_Size 4096
groupshared uint _FoWMap[FoWMap_Size];
[numthreads(32,1,1)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
for (uint i = 0; i < FoWMap_Size; i++)
{
_FoWMap[i] = i;
}
}
这就是我的环境。 有谁知道是否可以读回组共享数据,如果可以,那为什么我的缓冲区读回全是 0?
不,您不能直接访问 CPU 上的组共享内存。 Groupshared 内存是一块片上内存,顾名思义,它仅在单个组内的线程之间共享,因此甚至没有一个 groupshared 内存,而是多个实例(可能会也可能不会-存在,取决于硬件和着色器)。一旦它所属的线程组完成执行(这允许硬件为下一个线程组重新使用该内存),每个组共享内存块的生命周期就会结束。例如,在您的情况下,您实际上是在分派 ThreadCount
个组,因此会有那么多 16 kb 组共享内存的逻辑块,每个逻辑块的大小为 16 kb。
因此,总而言之,组共享内存更像是一个临时缓存,您可以使用它让线程组中的线程可以相互通信。除了线程组中的这 32 个线程之外,没有人知道该内存的内容甚至存在(因为它仅在这些线程当前执行时才真正存在)。
如果这 32 个线程之外的任何线程需要访问内存,您需要将其写出到 RW 缓冲区。