2015-02-28 3 views
1

Я действительно не могу понять, что здесь происходит.DX11 Compute Shader пишет только один индекс

У меня есть вычислительный шейдер, который принимает результат FFT (от реального входа) и вычисляет мощности каждого бина, сохраняя их в другом буфере (БПЛА). Реализация FFT - это библиотека D3DCSX.

Шейдер в вопросе:

struct Complex { 
    float real; 
    float imag; 
}; 

RWStructuredBuffer<Complex> g_result : register(u0); 
RWStructuredBuffer<float> g_powers : register(u1); 

[numthreads(1, 1, 1)] void main(uint3 id : SV_DispatchThreadID) { 
    const uint bin = id.x; 
    const float real = g_result[bin + 1].real; 
    const float imag = g_result[bin + 1].imag; 

    const float power = real * real + imag * imag; 
    const float mag = sqrt(power); 
    const float db = 10.0f * log10(1.0f + power); 

    g_powers[bin] = power; 
} 

код создания буфера:

//The buffer in which the resulting powers are stored (m_result_buffer1) 
buffer_desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE; 
buffer_desc.ByteWidth = sizeof(float) * NumBins(); 
buffer_desc.CPUAccessFlags = 0; 
buffer_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; 
buffer_desc.StructureByteStride = sizeof(float); 
buffer_desc.Usage = D3D11_USAGE_DEFAULT; 

hr = m_device->CreateBuffer (
    &buffer_desc, 
    nullptr, 
    &m_result_buffer1 
); HR_THROW(); 

//UAV for m_result_buffer1 
view_desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; 
view_desc.Buffer.FirstElement = 0; 
view_desc.Format = DXGI_FORMAT_R32_TYPELESS; 
view_desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW; 
view_desc.Buffer.NumElements = NumBins(); 

hr = m_device->CreateUnorderedAccessView (
    m_result_buffer1, 
    &view_desc, 
    &m_result_view 
); HR_THROW(); 

//Buffer for reading powers to the CPU 
buffer_desc.BindFlags = 0; 
buffer_desc.ByteWidth = sizeof(float) * NumBins(); 
buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; 
buffer_desc.MiscFlags = 0; 
buffer_desc.StructureByteStride = sizeof(float); 
buffer_desc.Usage = D3D11_USAGE_STAGING; 

hr = m_device->CreateBuffer (
    &buffer_desc, 
    nullptr, 
    &m_result_buffer2 
); HR_THROW(); 

Отправка код:

CComPtr<ID3D11UnorderedAccessView> result_view; 

hr = m_fft->ForwardTransform (
    m_sample_view, 
    &result_view 
); HR_THROW(); 

ID3D11UnorderedAccessView* views[] = { 
    result_view, //FFT UAV (u0) 
    m_result_view //Power UAV (u1) 
}; 

m_context->CSSetShader(m_power_cs, nullptr, 0); 
m_context->CSSetUnorderedAccessViews(0, 2, views, nullptr); 
m_context->Dispatch(NumBins(), 1, 1); 

И, наконец, отображения кода CPU:

m_context->CopyResource(m_result_buffer2, m_result_buffer1); 

D3D11_MAPPED_SUBRESOURCE sub = { 0 }; 

m_context->Map(m_result_buffer2, 0, D3D11_MAP_READ, 0, &sub); 
memcpy(result, sub.pData, sizeof(float) * NumBins()); 
m_context->Unmap(m_result_buffer2, 0); 

Что происходит, этот шейдер, кажется, имеет каждый поток, записываемый в один и тот же индекс в выходном буфере. Отображаемый буфер всегда считывает правильное значение для первого бункера, а затем 0.0f для каждого другого бункера. Эквивалентный код на процессоре работает нормально. Странно, что я установил условные обозначения и знаю, что bin не всегда равно 0, и что мощность каждого бина вне bin 0 также не всегда равна 0.0f. Я также пробовал писать несколько бункеров в одном потоке, используя цикл for, и то же самое происходит. Что я делаю не так?

У меня есть догадка, что это код создания буфера или код отображения, который находится в корне проблемы. Я знаю, что я использую правильное количество потоков на графическом процессоре и что идентификаторы отправки верны, это результат сбоя процессора, это неправильно.

ответ

0

Проблема решена!

Я использовал RWStructuredBuffer для представления RWByteOrderBuffer. Не совсем уверен, как это привело к такому результату, но так оно и было. Таким образом, результат FFT теперь равен RWByteOrderBuffer. Что было странно в этом буфере, тем не менее, был тот факт, что реализация D3DCSX разнесла значения float до сих пор друг от друга - возможно, по причинам кэша, но я честно не слишком уверен, почему. Это мой Compute Shader сейчас (вычислительный децибел вместо полномочий на этот раз - не связанные с изменениями):

RWByteAddressBuffer  g_result : register(u0); 
RWStructuredBuffer<float> g_decibels : register(u1); 

[numthreads(256, 1, 1)] void main(uint3 id : SV_DispatchThreadID) { 
    const float real = asfloat(g_result.Load(id.x * 8 + 0)); 
    const float imag = asfloat(g_result.Load(id.x * 8 + 4)); 

    const float power = real * real + imag * imag; 
    const float db = 10.0f * log10(1.0f + power); 

    g_decibels[id.x] = db; 
} 

Я изменил описание моих децибел буфера к тому из структурированного буфера, хотя, просто чтобы сделать вещи проще для меня:

buffer_desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE; 
buffer_desc.ByteWidth = sizeof(float) * NumBins(); 
buffer_desc.CPUAccessFlags = 0; 
buffer_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; 
buffer_desc.StructureByteStride = sizeof(float); 
buffer_desc.Usage = D3D11_USAGE_DEFAULT; 

hr = m_device->CreateBuffer (
    &buffer_desc, 
    nullptr, 
    &m_result_buffer1 
); HR_THROW(); 

view_desc.Buffer.FirstElement = 0; 
view_desc.Buffer.Flags = 0; 
view_desc.Buffer.NumElements = NumBins(); 
view_desc.Format = DXGI_FORMAT_UNKNOWN; 
view_desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; 

hr = m_device->CreateUnorderedAccessView (
    m_result_buffer1, 
    &view_desc, 
    &m_result_view 
); HR_THROW(); 

Вот почему g_decibels еще RWStructuredBuffer.

Неизвестный мне вопрос, важно ли, чтобы буфер результата считывался/записывался, когда нужны только обращения - если я меняю g_result на обычный ByteOrderBuffer Я не получаю никакого вывода. Но по крайней мере сейчас это работает.

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