Войти
ПрограммированиеФорумГрафика

Diligent Engine - современная кросс-платформенная низкоуровневая графическая библиотека (15 стр)

Страницы: 114 15 16 1722 Следующая »
#210
19:49, 5 ноя. 2019

innuendo
> смысл чтобы не было диспатчей одновременно в gfx и compute ?

Потому что они хотели контролировать что с чем перекрывается. В их случае они, кажется, делали light culling в компьюте и shadow pass в графике. Я, честно говоря, подзабыл детали.


#211
(Правка: 20:22) 20:20, 5 ноя. 2019

innuendo
> а может вообще не нужны барьеры ? лишний трах мозга, понимаешь :)

Иногда барьеры нужны. Классический пример - формирование мипмапов по четыре за раз.
Вот код шейдера от Микрософт который это делает:

Texture2D<float4> SrcMip : register(t0);
RWTexture2D<float4> OutMip[4] : register(u0);

SamplerState BilinearClamp : register(s0);

cbuffer CB : register(b1)
{
  uint  SrcMipLevel;  // Texture level of source mip
  uint  NumMipLevels;
  float2 TexelSize;  // 1.0 / OutMip1.Dimensions
  uint NON_POWER_OF_TWO;
}

groupshared float gs_R[64];
groupshared float gs_G[64];
groupshared float gs_B[64];
groupshared float gs_A[64];

void StoreColor(uint Index, float4 Color)
{
  gs_R[Index] = Color.r;
  gs_G[Index] = Color.g;
  gs_B[Index] = Color.b;
  gs_A[Index] = Color.a;
}

float4 LoadColor(uint Index)
{
  return float4(gs_R[Index], gs_G[Index], gs_B[Index], gs_A[Index]);
}

[numthreads(8, 8, 1)]
void CS(uint GI : SV_GroupIndex, uint3 DTid : SV_DispatchThreadID)
{
  float2 UV;
  float2 UV1;
  float2 Off;
  float2 O;

  float4 Src1;

  UV = TexelSize * (DTid.xy + 0.5);
  Src1 = SrcMip.SampleLevel(BilinearClamp, UV, SrcMipLevel);

  OutMip[0 + SrcMipLevel][DTid.xy] = Src1;

  if (NumMipLevels == 1)
    return;

  StoreColor(GI, Src1);
  GroupMemoryBarrierWithGroupSync();

  if ((GI & 0x9) == 0)
  {
    float4 Src2 = LoadColor(GI + 0x01);
    float4 Src3 = LoadColor(GI + 0x08);
    float4 Src4 = LoadColor(GI + 0x09);
    Src1 = 0.25 * (Src1 + Src2 + Src3 + Src4);

    OutMip[1 + SrcMipLevel][DTid.xy / 2] = Src1;

    StoreColor(GI, Src1);
  }

  GroupMemoryBarrierWithGroupSync();

  if ((GI & 0x1B) == 0)
  {
    float4 Src2 = LoadColor(GI + 0x02);
    float4 Src3 = LoadColor(GI + 0x10);
    float4 Src4 = LoadColor(GI + 0x12);
    Src1 = 0.25 * (Src1 + Src2 + Src3 + Src4);

    OutMip[2 + SrcMipLevel][DTid.xy / 4] = Src1;

    StoreColor(GI, Src1);
  }

  GroupMemoryBarrierWithGroupSync();

  if (GI == 0)
  {
    float4 Src2 = LoadColor(GI + 0x04);
    float4 Src3 = LoadColor(GI + 0x20);
    float4 Src4 = LoadColor(GI + 0x24);
    Src1 = 0.25 * (Src1 + Src2 + Src3 + Src4);

    OutMip[3 + SrcMipLevel][DTid.xy / 8] = Src1;
  }
}

Тут без барьеров не обойдешься.
А вот шейдер который делает то же самое, но без барьеров и один за проход:

Texture2DArray<float4> SrcTexture : register(t0);
RWTexture2DArray<float4> DstTexture : register(u0);
SamplerState BilinearClamp : register(s0);

cbuffer CB : register(b0)
{
  float4 TexelSize; 
  float ArraySize;
}

[numthreads( 16, 16, 1 )]
void CS(uint3 DTid : SV_DispatchThreadID)
{
  float3 coord = float3(TexelSize.xy * (DTid.xy + 0.5), 0);

  for(int i = 0; i < ArraySize; i++)
  {
    coord.z = i;
    uint3 pos = uint3(DTid.xy, i);
    DstTexture[pos] = SrcTexture.SampleLevel(BilinearClamp, coord, 0);
  }
}
Как бы попроще. Разницу в производительности не удалось найти даже под микроскопом, хотя использовались текстуры 8192х8192.
Бывает что без барьеров не обойтись, но редко.

Только я не понял чего тебя так волнуют барьеры, когда речь изначально шла о разнице в производительности между DX11 и DX12?
Ты еще советовал синхронизировать независимые очереди в DX12, т.е убрать его преимущество перед DX11. Хотя у меня упорно закрадывается подозренние, что очередями ты называешь выполнение командных листов ибо барьеры тормозят выполнение оных, а никак не другую очередь. Разные очереди (а их всего три) можно синхронизировать только через CPU.

Кстати на картинке что я привел, имеется еще одна очередь - High Priority Compute Queue которую запускает Oculus Server. Такую фичу ввели в Liquid VR, более я их нигде не встречал. Думаю что Окулус обнаружив AMD видеокарту переключается на Liquid VR и компьют с высоким приоритетом, что еще добавляет производительности. На Nvidia этого нет и там сервер сует свои команды в графическую очередь, что вообще-то не лучшее решение. Вообще компьюты можно выполнять и в графической очереди, часто это имеет смысл. То же самое с copyQueue. Вот обратный процесс (запустить графический конвейер в computQueue) наверно невозможен, хотя я и не пробовал.

#212
20:29, 5 ноя. 2019

san
> Бывает что без барьеров не обойтись, но редко.

можно было не писать код, а просто написать для чего нужны

> Ты еще советовал синхронизировать независимые очереди в DX12, т.е убрать его
> преимущество перед DX11. Хотя у меня упорно закрадывается подозренние, что
> очередями ты называешь выполнение командных листов ибо барьеры тормозят
> выполнение оных, а никак не другую очередь.

ты видать лучше знаешь что у меня в голове

это не я советую, ты хоть смотрел примеры по ссылке из msdn ?

#213
20:30, 5 ноя. 2019

san
> Тут без барьеров не обойдешься.
> А вот шейдер который делает то же самое, но без барьеров и один за проход:

Что-то я вообще не понял, как эти шейдеры сравниваются.  Один генерирует по 4 мип уровня в текстуре in-place, а другой из одного массива переписывает в другой. Вроде абсолютно разные вещи.
У Майкрософта, кстати, в их хостовой части есть баг - они не делают барьеры при переходе от UAV к SRV.

#214
(Правка: 20:37) 20:31, 5 ноя. 2019

innuendo
> а можно ссылочку на доки что могут параллельно два диспатча из той же очереди?
https://www.khronos.org/registry/vulkan/specs/1.1/html/chap6.html… mission-order

Action and synchronization commands recorded to a command buffer execute the VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT pipeline stage in submission order - forming an implicit execution dependency between this stage in each command.

Команды последовательно выполняют top of pipe stage, больше никаких гарантий не дается. Дополнительные гарантии дает барьер, так что если нет барьеров то все выполняется параллельно насколько это возможно.

Вот еще
Unless otherwise specified, and without explicit synchronization, the various commands submitted to a queue via command buffers may execute in arbitrary order relative to each other, and/or concurrently. Also, the memory side-effects of those commands may not be directly visible to other commands without explicit memory dependencies.

+ картинка
#215
20:43, 5 ноя. 2019

/A\
> Команды последовательно выполняют top of pipe stage, больше никаких гарантий не
> дается.

> in submission order

> and/or concurrently.

ok

#216
20:45, 5 ноя. 2019

кстати, судя по коду UE на конзолях можно указывать бюджет - что будет в основном выполняться: gfx или compute

#217
20:46, 5 ноя. 2019

innuendo
> > in submission order
Только порядок в котором команды будут переданы на GPU.

Submission order is a fundamental ordering in Vulkan, giving meaning to the order in which action and synchronization commands are recorded and submitted to a single queue.
#218
20:55, 5 ноя. 2019

assiduous
> Что-то я вообще не понял, как эти шейдеры сравниваются.  Один генерирует по 4 мип уровня в текстуре in-place, а другой из одного массива переписывает в другой.

И то и другое это генерация мипмапов. В первом случае это делается порциями по 4, для чего нужны барьеры, во втором шейдер вызывается для каждого уровня. Результат идентичен, время работы тоже.

#219
21:01, 5 ноя. 2019

san
> И то и другое это генерация мипмапов. В первом случае это делается порциями по
> 4, для чего нужны барьеры, во втором шейдер вызывается для каждого уровня.
> Результат идентичен, время работы тоже.
Только во втором случае тебе надо иметь копию твоего массива текстур (подход как в d3d11), а в первом это делается in-place без дополнительного расхода памяти. Барьер тебе все-равно понадобится, когда ты захочешь использовать текстуру как SRV.

#220
(Правка: 22:05) 22:03, 5 ноя. 2019

assiduous
> Только во втором случае тебе надо иметь копию твоего массива текстур (подход как в d3d11), а в первом это делается in-place без дополнительного расхода памяти.
Ничего подобного. Зачем мне второй набор текстур? Походу в цикле создаются ShaderResourceView и UnorderedAccessView на каждый мип-уровень и все. Текстура одна.

>Барьер тебе все-равно понадобится, когда ты захочешь использовать текстуру как SRV.
Барьер стоит на переход к D3D12_RESOURCE_STATE_UNORDERED_ACCESS. Но это совсем не тот барьер что в шейдере, это изменение состояния ресурса и ничего общего с выравниванием тредов не имеет.

Вот тебе весь код генерации мипов для второго случая:

  {
    //Transition from pixel shader resource to unordered access
    Command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_Texture, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_UNORDERED_ACCESS));

    //Loop through the mipmaps copying from the bigger mipmap to the smaller one with downsampling in a compute shader
    for (int TopMip = 0; TopMip < NumMips - 1; TopMip++)
    {
      //Get mipmap dimensions
      uint32_t dstWidth = max((width >> (TopMip + 1)), 1);
      uint32_t dstHeight = max(height >> (TopMip + 1), 1);

      //Create shader resource view for the source texture in the descriptor heap
      srcTextureSRVDesc.Format = desc.Format;
      srcTextureSRVDesc.Texture2DArray.MipLevels = 1;
      srcTextureSRVDesc.Texture2DArray.MostDetailedMip = TopMip;
      srcTextureSRVDesc.Texture2DArray.ArraySize = desc.DepthOrArraySize;
      m_context->m_Device->CreateShaderResourceView(m_Texture, &srcTextureSRVDesc, currentCPUHandle);
      currentCPUHandle.Offset(1, descriptorSize);

      //Create unordered access view for the destination texture in the descriptor heap
      destTextureUAVDesc.Format = desc.Format;
      destTextureUAVDesc.Texture2DArray.MipSlice = TopMip + 1;
      destTextureUAVDesc.Texture2DArray.ArraySize = desc.DepthOrArraySize;
      m_context->m_Device->CreateUnorderedAccessView(m_Texture, nullptr, &destTextureUAVDesc, currentCPUHandle);
      currentCPUHandle.Offset(1, descriptorSize);

      //Pass the destination texture pixel size to the shader as constants
      Command_list->SetComputeRoot32BitConstant(0, DWParam(1.0f / dstWidth).Uint, 0);
      Command_list->SetComputeRoot32BitConstant(0, DWParam(1.0f / dstHeight).Uint, 1);
      Command_list->SetComputeRoot32BitConstant(0, DWParam((float)left/width).Uint, 2);
      Command_list->SetComputeRoot32BitConstant(0, DWParam((float)right/width).Uint, 3);
      Command_list->SetComputeRoot32BitConstant(0, DWParam((float)desc.DepthOrArraySize).Uint, 4);

      //Pass the source and destination texture views to the shader via descriptor tables
      Command_list->SetComputeRootDescriptorTable(1, currentGPUHandle);
      currentGPUHandle.Offset(1, descriptorSize);
      Command_list->SetComputeRootDescriptorTable(2, currentGPUHandle);
      currentGPUHandle.Offset(1, descriptorSize);

      //Dispatch the compute shader with one thread per 16x16 pixels
      Command_list->Dispatch(max(dstWidth / 8, 1u), max(dstHeight / 8, 1u), 1);

      //Wait for all accesses to the destination texture UAV to be finished before generating the next mipmap, as it will be the source texture for the next mipmap
      Command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::UAV(m_Texture));
    }

    //When done with the texture, transition it's state back to be a pixel shader resource
    Command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_Texture, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COMMON));
  };

  //Close and submit the command list
    hr = comput ? mipmap_context->ComputPresent(true) : mipmap_context->Present(true); 
  return hr;

Где тут дополнительный расход памяти?

#221
22:05, 5 ноя. 2019

san
> Но это совсем не тот барьер что в шейдере

что такое барьер  в шейдере ?

#222
22:14, 5 ноя. 2019

san
Я же сказал, что в этом коде баг. Ты не можешь использовать мип-уровень как шейдер ресурс если до этого он был UAV. Нужен барьер.
Запусти код вот с этим:
https://docs.microsoft.com/en-us/windows/win32/direct3d12/using-d… ed-validation

#223
22:15, 5 ноя. 2019

innuendo
Он имеет в виду GroupMemoryBarrierWithGroupSync

#224
22:19, 5 ноя. 2019

assiduous
> Он имеет в виду GroupMemoryBarrierWithGroupSync

я так и подумал :)  хотя есть и barrier в glsl

Страницы: 114 15 16 1722 Следующая »
ПрограммированиеФорумГрафика