2013-04-25 2 views
2

Может ли кто-нибудь сказать мне, возможен ли в DirectX 11 следующий вычислительный шейдер?Compute shader: читать данные, записанные в одном потоке из другого?

Я хочу, чтобы первый поток в диспетчере, который обращается к элементу в буфере (g_positionsGrid), чтобы установить (сравнить обмен) этот элемент с временным значением, чтобы обозначить, что он предпринимает некоторые действия.

В этом случае значение temp равно 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; 

     } 
    } 
} 

ответ

2

синхронизации потоков в DirectCompute очень легко, но по сравнению с теми же функциями, чтобы ЦП многопоточности очень unflexible. AFAIK, единственный способ синхронизации данных между потоками в вычислительном шейдере - использовать память groupshared и GroupMemoryBarrierWithGroupSync(). Это означает, что вы можете:

  • создать небольшой временный буфер в groupshared памяти
  • значение высчитывает
  • запись в groupshared буфер
  • синхронизации потоков с GroupMemoryBarrierWithGroupSync()
  • считанных из groupshared из другого потока и использования это как-то

Чтобы реализовать все это, вы n eed надлежащие индексы массива. Но где вы можете это взять? В значениях DirectCompute, переданных в Dispatch, и системных значениях, которые вы можете получить в шейдере (SV_GroupIndex, SV_DispatchThreadID, SV_GroupThreadID, SV_GroupID) related. Используя эти значения, вы можете рассчитать индексы для оценки буферов.

Compute шейдеры не хорошо документированы, и нет простого способа, но, чтобы узнать больше информации по крайней мере, вы можете:

  • чтение MSDN: Compute shader overview
  • часам DirectCompute Lecture Series видео на Channel9
  • исследовать вычисления шейдерные образцы от DirectX SDK, очень хорошо образцы от NVIDIA`s SDK (10 и 11)
  • this передовая бумага NVIDIA, где они были реализованы t hread, а затем оптимизировать их код, чтобы работать в 10 раз быстрее;)

С вашего кода. Возможно, вы можете немного переделать его.

  1. Это всегда хорошо для всех потоков выполнять ту же задачу. Симметричная загрузка. На самом деле, вы не можете назначать разные задачи для своих потоков, как это делается в коде ЦП.

  2. Если данные первым нужна предварительная обработка и дальнейшая обработка, вы можете разделить его на differrent Dispatch() звонки (разные шейдеры), что вы будете называть в последовательности:

    • preprocessShader считывает из буфера inputData и пишет preprocessedData
    • calculateShader feads из preprocessedData и пишет finalData

    в этом случае лет u может отказаться от любой медленной синхронизации потоков и медленной общей памяти.

  3. Посмотрите на трюк «Редукция», упомянутый выше.

Надеюсь, это поможет! И счастливое кодирование!

Смежные вопросы