计算着色器:从另一个线程读取一个线程中写入的数据?

问题描述 投票:0回答:2

有人可以告诉我以下计算着色器是否可以用于 DirectX 11?

我希望 Dispatch 中的第一个线程访问缓冲区 (g_positionsGrid) 中的元素来设置(比较交换)该元素与临时值,以表示它正在采取某些操作。

在本例中,临时值为 0xffffffff,第一个线程将继续从结构化附加缓冲区 (g_positions) 中分配一个值,并将其分配给该元素。

所以到目前为止一切都很好,但是调度中的其他线程可以进入比较交换和第一个线程的分配之间,因此需要等待分配索引可用。我通过繁忙的等待(即 while 循环)来完成此操作。

然而遗憾的是,这只是锁定了 GPU,因为我假设第一个线程写入的值不会传播到陷入 while 循环中的其他线程。

有什么方法可以让这些线程看到该值吗?

感谢您的帮助!

RWStructuredBuffer<float3> g_positions : register(u1);
RWBuffer<uint> g_positionsGrid : register(u2);

void AddPosition( uint address, float3 pos )
{
    uint token = 0; 

    // Assign a temp value to signify first thread has accessed this particular element
    InterlockedCompareExchange(g_positionsGrid[address], 0, 0xffffffff, token);

    if(token == 0)
    {
        //If first thread in here allocate index and assign value which
        //hopefully the other threads will pick up
        uint index = g_positions.IncrementCounter();
        g_positionsGrid[address] = index;
        g_positions[index].m_position = pos;
    }
    else
    {
        if(token == 0xffffffff)
        {
            uint index = g_positionsGrid[address];

            //This never meets its condition
            [allow_uav_condition]
            while(index == 0xffffffff) 
            { 
                //For some reason this thread never gets the assignment
                //from the first thread assigned above
                index = g_positionsGrid[address]; 
            }

            g_positions[index].m_position = pos;
        }
        else
        {
            //Just assign value as the first thread has already allocated a valid slot 
            g_positions[token].m_position = pos;

        }
    }
}
directx compute-shader
2个回答
1
投票

DirectCompute 中的线程同步非常容易,但与 CPU 线程的相同功能相比非常不灵活。 AFAIK,在计算着色器中的线程之间同步数据的唯一方法是使用

groupshared
内存和
GroupMemoryBarrierWithGroupSync()
。这意味着您可以:

  • 在内存
    groupshared
    内存中创建小型临时缓冲区
  • 计算值
  • 写入
    groupshared
    缓冲区
  • 使用
    GroupMemoryBarrierWithGroupSync()
  • 同步线程
  • 从另一个线程读取
    groupshared
    并以某种方式使用它

要实现所有这些东西,您需要适当的数组索引。但你可以从哪里获取它呢?在 DirectCompute 中,传入Dispatch的值以及您可以在着色器中获取的系统值(SV_GroupIndex、SV_DispatchThreadID、SV_GroupThreadID、SV_GroupID)相关。使用该值,您可以计算索引来评估您的缓冲区。

计算着色器没有很好的文档记录,并且没有简单的方法,但要查找更多信息至少可以:

从你的代码开始。好吧,也许你可以稍微重新设计一下。

  1. 所有线程执行相同的任务总是好的。对称加载。实际上,您不能像在 CPU 代码中那样为线程分配不同的任务。

  2. 如果您的数据首先需要进行一些预处理,然后进一步处理,您可能需要将其划分为按顺序调用的不同 Dispatch() 调用(不同的着色器):

    • preprocessShader
      从缓冲区
      inputData
      读取并写入
      preprocessedData
    • calculateShader
      preprocessedData
      馈送并写入
      finalData

    在这种情况下,您可以放弃任何慢速线程同步和慢速组共享内存。

  3. 看看上面提到的“线程减少”技巧。

希望有帮助!祝您编码愉快!


0
投票

我只是来这里问你如何从计算着色器中的追加缓冲区读取数据?您声明 g_positions 是一个追加缓冲区,并通过引用索引 (g_positions[value]) 在代码中访问它。您是否首先在不同的计算着色器中附加到此缓冲区?我目前正在尝试了解如何追加到追加缓冲区,然后在计算着色器中读取该追加缓冲区,而无需传递到 cpu?

© www.soinside.com 2019 - 2024. All rights reserved.