我正在尝试编写一个卷积滤波器,它使用特定的函数来确定像素的确切输出颜色。有谁知道是否可以定义一个可以在parallel_for_each
块中使用的函数?
2 回答
一个函数必须遵循许多规则才能使用restrict(amp) 成功编译。第一个,如 parallel_for_each() 部分所述,涉及它调用的函数。这些必须在代码生成时可见,并且还必须用限制(amp)标记。如果您不使用链接时间代码生成,这实质上意味着它们必须在编译时位于同一个 .cpp 文件中,可能来自该 .cpp 文件中包含的头文件。如果在编译两个 .cpp 文件(调用函数的文件和实现函数的文件)以及链接时都使用 /ltcg,则可以将调用函数和被调用函数保存在单独的文件中。
C++ AMP 兼容函数或 lambda 只能使用 C++ AMP 兼容类型,包括以下内容:
- 整数
- 无符号整数
- 漂浮
- 双倍的
- C 样式的 int、unsigned int、float 或 double 数组
- concurrency::array_view 或对 concurrency::array 的引用
- 仅包含 C++ AMP 兼容类型的结构
这意味着某些数据类型是被禁止的:
- bool(可用于 lambda 中的局部变量)
- 字符
- 短的
- 长长的
- 以上的未签名版本
引用和指针(指向兼容类型)可以在本地使用,但不能被 lambda 捕获。不允许使用函数指针、指针到指针等;既不是静态变量也不是全局变量。
如果您希望使用它们的实例,类必须满足更多规则。它们必须没有虚函数或虚继承。允许使用构造函数、析构函数和其他非虚拟函数。成员变量必须都是兼容的类型,当然可以包括其他类的实例,只要这些类符合相同的规则。
您的 amp 兼容函数中的实际代码未在 CPU 上运行,因此无法执行您可能习惯执行的某些操作:
- 递归
- 指针铸造
- 使用虚函数
- 新建或删除
- RTTI 或动态投射
这是一个示例,它完全符合您的想法,但不使用平铺。该shift
参数是方形像素掩码的大小(半径)。在此示例中,我不会尝试为如此接近数组边缘的元素计算新值。为了不在这些没有工作的元素上浪费线程,parallel_for_each
需要一个shift * 2
小于数组的元素的范围。更正后的索引会根据范围idc
调整idx
值以引用正确的元素。
void MatrixSingleGpuExample(const int rows, const int cols, const int shift)
{
// Initialize matrices
std::vector<float> vA(rows * cols);
std::vector<float> vC(rows * cols);
std::iota(vA.begin(), vA.end(), 0.0f);
// Calculation
accelerator_view view = accelerator(accelerator::default_accelerator).default_view;
double time = TimeFunc(view, [&]()
{
array_view<const float, 2> a(rows, cols, vA);
array_view<float, 2> c(rows, cols, vC);
c.discard_data();
extent<2> ext(rows - shift * 2, cols - shift * 2);
parallel_for_each(view, ext, [=](index<2> idx) restrict(amp)
{
index<2> idc(idx[0] + shift, idx[1] + shift);
c[idc] = WeightedAverage(idc, a, shift);
});
c.synchronize();
});
}
float WeightedAverage(index<2> idx, const array_view<const float, 2>& data, int shift)
restrict(amp)
{
if (idx[1] < shift || idx[1] >= data.extent[1] - shift)
return 0.0f;
float max = fast_math::sqrtf((float)(shift * shift * 2));
float avg = 0.0;
float n = 0.0f;
for (int i = -shift; i <= shift; ++i)
for (int j = -shift; j <= shift; ++j)
{
int row = idx[0] + i;
int col = idx[1] + i;
float scale = 1 - fast_math::sqrtf((float)((i * i) * (j * j))) / max;
avg += data(row,col) * scale;
n += 1.0f;
}
avg /= n;
return avg;
}
是的,如果您希望能够从 CPU 代码调用相同的函数,则需要使用 restrict(amp) 或 restrict(cpu, amp) 注释函数签名。请参阅有关限制的 MSDN 文档。