HLSL компилятор пропускает важные утверждения - PullRequest
0 голосов
/ 02 июня 2018

У меня есть этот вычислительный шейдер, который пересекает двоичное дерево.Раньше он прекрасно работал с отдельно установленным DirectX SDK (июнь), с компилятором № 43.

Компиляторы № 46 и № 47 (из Windows SDK 8.0 и 8.1 соответственно), однако, похоже, что в них отсутствуют два действительно важныхстроки кода, в которых шейдер работает по кругу, снова и снова проверяя одни и те же узлы дерева, пока Windows не перезапустит графический драйвер (проверено разборкой).

Вот минимальный пример кода, демонстрирующий такое поведение:

#define LEFT_PROCESSED  1
#define RIGHT_PROCESSED 2

struct Node
{
  float4 min;
  float4 max;
  int left;
  int right;
  int parent;
  int flags;
};

RWStructuredBuffer<Node> tree: register(u0);

bool TreeSearch()
{
  Node node = tree[0];

  int nodeId = 0;

  int statusStack[40];
  int stackSize = 0;
  statusStack[0] = 0;

  while (true)
  {
    if (!(statusStack[stackSize] & LEFT_PROCESSED))
    {
      statusStack[stackSize] |= LEFT_PROCESSED;
      ++stackSize;
      statusStack[stackSize] = 0;
      nodeId = node.left;
      node = tree[nodeId];
      continue;
    }

    if (!(statusStack[stackSize] & RIGHT_PROCESSED))
    {
      statusStack[stackSize] |= RIGHT_PROCESSED; // this line
      ++stackSize;
      statusStack[stackSize] = 0;                // and this line
      nodeId = node.right;
      node = tree[nodeId];
      continue;
    }

    if (node.parent != -1)
    {
      --stackSize;
      nodeId = node.parent;
      node = tree[nodeId];
    }
    else
      return false;
  }
  return false;
}

[numthreads(32, 1, 1)]
void CSSearch(uint2 dispatchThreadId: SV_DispatchThreadID)
{
  TreeSearch();
}

И соответствующая сборка:

cs_5_0
dcl_globalFlags refactoringAllowed
dcl_uav_structured u0, 48
dcl_temps 3
dcl_indexableTemp x0[40], 4
dcl_thread_group 32, 1, 1
ld_structured_indexable(structured_buffer, stride=48)(mixed,mixed,mixed,mixed) r0.xyz, l(0), l(32), u0.xyzx
mov x0[0].x, l(0)
mov r1.xyz, r0.yzxy
mov r0.w, l(0)
loop 
  mov r1.w, x0[r0.w + 0].x
  and r2.x, r1.w, l(1)
  if_z r2.x
    or r1.w, r1.w, l(1)       // here's the first one in the LEFT branch
    mov x0[r0.w + 0].x, r1.w  //
    iadd r1.w, r0.w, l(1)
    mov x0[r1.w + 0].x, l(0)  // and the second one
    ld_structured_indexable(structured_buffer, stride=48)(mixed,mixed,mixed,mixed) r2.xyz, r1.z, l(32), u0.yzxx
    mov r1.xyz, r2.xyzx
    mov r0.w, r1.w
    continue 
  endif 
  mov r1.w, x0[r0.w + 0].x   // why is there nothing in the RIGHT branch?
  and r1.w, r1.w, l(2)
  if_z r1.w
    iadd r1.w, r0.w, l(1)
    ld_structured_indexable(structured_buffer, stride=48)(mixed,mixed,mixed,mixed) r2.xyz, r1.x, l(32), u0.yzxx
    mov r1.xyz, r2.xyzx
    mov r0.w, r1.w
    continue 
  endif 
  ine r1.w, r1.y, l(-1)
  if_nz r1.w
    iadd r0.w, r0.w, l(-1)
    ld_structured_indexable(structured_buffer, stride=48)(mixed,mixed,mixed,mixed) r1.xyz, r1.y, l(32), u0.yzxx
  else 
    break 
  endif 
endloop 
ret 

Когда я опускаю первый continue, он генерирует код для этих двух строк, но затем он также прерывается.

Есть идеи, как заставить новый компилятор генерировать этот код?

1 Ответ

0 голосов
/ 02 июня 2018

Обратите внимание: я не знаком с программированием на GPU и не уверен, что это ошибка компилятора или кода.Следующее является просто обходным путем.

Вы можете имитировать поведение continue, используя явную переменную, в надежде, что компилятор не помешает:

bool TreeSearch()
{
  Node node = tree[0];

  int nodeId = 0;

  int statusStack[40];
  int stackSize = 0;
  statusStack[0] = 0; 

  while (stackSize < 10) // Changed to make it compile.
  {
    int shouldContinue = 1;
    if (!(statusStack[stackSize] & LEFT_PROCESSED))
    {
      statusStack[stackSize] |= LEFT_PROCESSED;
      ++stackSize;
      statusStack[stackSize] = 0;
      nodeId = node.left;
      node = tree[nodeId];
      shouldContinue = 0;
    }

    if (shouldContinue && 
        !(statusStack[stackSize] & RIGHT_PROCESSED))
    {
      statusStack[stackSize] |= RIGHT_PROCESSED; // this line
      ++stackSize;
      statusStack[stackSize] = 0;                // and this line
      nodeId = node.right;
      node = tree[nodeId];
      shouldContinue = 0;
    }

    if (shouldContinue)
    { 
        if (node.parent != -1)
        {
          --stackSize;
          nodeId = node.parent;
          node = tree[nodeId];
        }
        else
          return false;
    }

  }
  return false;
}

РазборкаВ выводе, похоже, отсутствует какая-либо операция, отсутствующая в исходном фрагменте.Однако это может привести к дополнительным затратам.

Ссылка: http://shader -playground.timjones.io / 6abdc64cdf98e1840a3b38c629b4e217

...