DX11计算着色器只写入一个索引
DX11 Compute Shader writes only to one index
我真的不明白这里发生了什么。
我有一个计算着色器,它接收FFT结果(来自实际输入)并计算每个bin的幂,将它们存储在不同的缓冲区(UAV)中。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);
所发生的情况是,该着色器似乎使每个线程都写入输出缓冲区中的同一索引。映射的缓冲区总是为第一个bin读取正确的值,然后每隔一个bin读取0.0f。CPU上的等效代码运行得很好。奇怪的是,我放置了条件句,并且知道bin
并不总是0,bin 0之外的每个bin的幂也不总是0.0f。我还尝试使用for循环在同一线程上写入多个bin,但同样的事情也发生了。我做错了什么?
我有一种预感,缓冲区创建代码或映射代码是问题的根源。我知道我在GPU上运行了正确数量的线程,并且调度ID是正确的,这是CPU方面的错误结果。
问题已解决!
我使用RWStructuredBuffer
来表示RWByteOrderBuffer
。不完全确定这是如何导致这一结果的,但确实如此。因此,FFT结果现在是RWByteOrderBuffer
。然而,这个缓冲区的奇怪之处在于,D3DCSX实现将浮点值间隔得如此之远——可能是出于缓存的原因,但我真的不太确定为什么。这是我现在的计算着色器(这次计算分贝而不是功率——一个无关的变化):
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
,我将不会得到输出。但至少它现在起作用了。
- 给定一个向量,如何找到该向量的所有子集和的原始索引
- 在矢量中使用擦除时双重释放或损坏(快速顶部).如何擦除一个矢量的几个项目知道它们的索引?
- 一个 2D 数组,并按行存储值.第一个循环用于行索引,第二个循环用于列索引
- 如何访问委托的paint()函数中的另一个索引?
- 查找下一个具有真值C++的数组索引
- CPP:如何获取字符的最后一个索引
- 是否有一个类似STL的函数来用索引的某个函数填充数组
- 我正在尝试将我的 c++ 数组从第二个索引切到最后一个索引
- 如何根据另一个向量中给出的索引拆分向量?
- 如何用索引命名一个变量来存储输入 mxArray?
- "如何使用C++将字符串的第一个和最后一个索引返回到向量中?
- 查找数组的第一个和最后一个索引,其中 from 和 to 元素的顺序总和最大
- 数组:如何在指定索引之前显示数组的第一个和最后一个元素以及数组元素的差异?
- 数组 - 最后一个索引
- C++:检查向量中的元素是否大于另一个具有相同索引的元素的有效方法?
- 创建一个没有指针但有索引的链表
- 在向量C++中查找特定的第一个和最后一个索引<float>
- 编写一个递归功能,该功能采用数组并以相反顺序显示元素,而无需在末尾启动数组的索引
- 在C 字符串中,为什么在最后一个字符之后,通过索引和()访问索引时行为是不同的
- 如何给枚举值的索引一个得到它?