Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Unity3d hlsl CG计算着色器竞赛条件_Unity3d_Shader_Hlsl_Compute Shader - Fatal编程技术网

Unity3d hlsl CG计算着色器竞赛条件

Unity3d hlsl CG计算着色器竞赛条件,unity3d,shader,hlsl,compute-shader,Unity3d,Shader,Hlsl,Compute Shader,我试图通过unity/CG/hlsl中的计算着色器将纹理变换到频域,也就是说,我试图从纹理中读取像素值并输出基函数系数数组。我该怎么做呢?我对计算着色器是个新手,所以我有点迷路了。我理解竞争条件的原因以及计算着色器如何分配工作负载,但是有什么方法可以解决这个问题吗?一般来说,对于没有这方面背景的人来说,关于缓冲区和其他方面的文档似乎有点令人失望 我得到的错误是: < Calp>计算中的着色器错误:检测到共享资源的RACE条件写入,考虑将此写入条件。在Compute.Compute(xxx)(在d

我试图通过unity/CG/hlsl中的计算着色器将纹理变换到频域,也就是说,我试图从纹理中读取像素值并输出基函数系数数组。我该怎么做呢?我对计算着色器是个新手,所以我有点迷路了。我理解竞争条件的原因以及计算着色器如何分配工作负载,但是有什么方法可以解决这个问题吗?一般来说,对于没有这方面背景的人来说,关于缓冲区和其他方面的文档似乎有点令人失望

我得到的错误是: < Calp>计算中的着色器错误:检测到共享资源的RACE条件写入,考虑将此写入条件。在Compute.Compute(xxx)(在d3d11上)的内核testBuffer上

一个简化的例子是将所有像素值相加,目前我的方法如下。我正在尝试使用structuredbuffers,因为我不知道如何检索数据或将其存储在gpu上,以便以后进行全局着色器访问???

struct valueStruct{
float4 values[someSize];
}

RWStructuredBuffer<valueStruct> valueBuffer;

// same behaviour if using RWStructuredBuffer<float3> valueBuffer;
// if using 'StructuredBuffer<float3> valueBuffer;' i get the error:
// Shader error in 'Compute.compute': l-value specifies const object at kernel testBuffer at Compute.compute(xxx) (on d3d11)

Texture2D<float4> Source;

[numthreads(8, 8, 1)]
void testBuffer(uint3 id : SV_DispatchThreadID) {

      valueBuffer[0].values[0] +=  Source[id.xy];  // in theory the vaules 
      valueBuffer[0].values[1] +=  Source[id.xy];  // would be different
      valueBuffer[0].values[2] +=  Source[id.xy];  // but it doesn't really 
      valueBuffer[0].values[3] +=  Source[id.xy];  // matter for this, so 
      valueBuffer[0].values[4] +=  Source[id.xy];  // they are just Source[id.xy]
      //.....

}
不要使用structuredbuffer,但是在这种情况下,我不知道如何在内核分派之后检索数据。如果我使用的是RWStructuredBuffer的读取部分,那么我只能写入的等效缓冲区是什么?因为我没有真正阅读数据。或者无论发生什么情况,通用运算符“+=”是否已经导致了竞争条件

从谷歌我发现一个解决方案可能是使用
GroupMemoryBarrierWithGroupSync()??但我不知道这是什么(更不用说它是如何工作的),一般来说,谷歌结果只是在我头上飞了一点

有谁能举例说明如何解决这个问题?
否则我会通知任何指示

首先,每当一个线程向内存位置写入,而另一个线程从该位置读取或写入时,就会发生争用情况。因此,是的,
+=
已经造成了竞争状况,没有“简单”的方法来解决这个问题。(顺便说一句:
+=
隐式读取该值,因为您无法在不知道两个值的情况下计算它们的总和)

GroupMemoryBarrierWithGroupSync()
插入内存屏障,这意味着:当前线程停止在该行,直到当前组中的所有线程都到达该行。如果一个线程向内存位置写入,而另一个线程需要从该位置读取,则这一点非常重要。因此,它本身对您毫无帮助(但在以下算法中是必需的)

现在,计算所有像素(或任何类似像素)之和的常见解决方案是并行计算和。其思想是每个线程读取两个
像素,并将它们的总和写入
groupshared
数组中自己的索引(注意:不会发生争用情况,因为每个线程都有自己的内存要写入,没有两个线程写入同一位置)。然后,一半的线程从这个数组中读取每两个值,然后写回它们的和,依此类推,直到只剩下一个值。此时,我们计算了该组覆盖区域内所有像素的总和(在您的情况下,我们求和了8x8=64像素)。现在,该组中的一个线程(例如,
SV_GroupIndex
为零,这仅对每个组中的第一个线程有效)将该和写回该线程组特定索引处的
RWStructuredBuffer
(因此,同样,没有发生争用条件)。然后重复此过程,直到所有值相加

关于该算法的更深入的解释,请参见(注意,他们的代码是CUDA,因此尽管在HLSL中工作非常相似,但语法和函数名可能会有所不同)

现在,这只是计算所有像素的总和。计算频域可能有点复杂,甚至需要一个不同的解决方案,因为每组
groupshared
内存的总大小是有限的(DX10硬件上为16KB)

编辑:

HLSL中的小样本代码(假设图像已加载到线性结构Buffer中),计算128个连续像素的总和:

StructuredBuffer<float> Source : register(t0);
RWStructuredBuffer<float> Destination : register(u0);
groupshared float TotalSum[64];

[numthreads(64,1,1)]
void mainCS(uint3 groupID : SV_GroupID, uint3 dispatchID : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
{
    uint p = dispatchID.x * 2;
    float l = Source.Load(p);
    float r = Source.Load(p + 1);
    TotalSum[groupIndex] = l + r;
    GroupMemoryBarrierWithGroupSync();
    for(uint k = 32; k > 0; k >>= 1)
    {
        if(groupIndex < k)
        {
            TotalSum[groupIndex] += TotalSum[groupIndex + k];
        }
        GroupMemoryBarrierWithGroupSync();
    }
    if(groupIndex == 0) { Destination[groupID.x] = TotalSum[0]; }
}
StructuredBuffer源:寄存器(t0);
RWStructuredBuffer目的地:寄存器(u0);
groupshared float TotalSum[64];
[numthreads(64,1,1)]
void mainCS(uint3组id:SV_组id,uint3调度id:SV_调度线程id,uint组索引:SV_组索引)
{
uint p=调度ID.x*2;
浮点数l=电源负载(p);
浮点数r=源荷载(p+1);
总和[groupIndex]=l+r;
GroupMemoryBarrierWithGroupSync();
对于(uint k=32;k>0;k>>=1)
{
if(groupIndex
StructuredBuffer<float> Source : register(t0);
RWStructuredBuffer<float> Destination : register(u0);
groupshared float TotalSum[64];

[numthreads(64,1,1)]
void mainCS(uint3 groupID : SV_GroupID, uint3 dispatchID : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
{
    uint p = dispatchID.x * 2;
    float l = Source.Load(p);
    float r = Source.Load(p + 1);
    TotalSum[groupIndex] = l + r;
    GroupMemoryBarrierWithGroupSync();
    for(uint k = 32; k > 0; k >>= 1)
    {
        if(groupIndex < k)
        {
            TotalSum[groupIndex] += TotalSum[groupIndex + k];
        }
        GroupMemoryBarrierWithGroupSync();
    }
    if(groupIndex == 0) { Destination[groupID.x] = TotalSum[0]; }
}