可以在通用 Windows 平台(UWP)应用中使用 C++ AMP(C++ 加速大规模并行度)在 GPU(图形处理单元)或其他计算加速器上执行计算。 但是,C++ AMP 不提供用于直接使用 Windows 运行时类型的 API,而 Windows 运行时不提供 C++ AMP 的包装器。 在代码中使用 Windows 运行时类型(包括自己创建的类型)时,必须将这些类型转换为与 C++ AMP 兼容的类型。
注释
从 Visual Studio 2022 版本 17.0 开始,已弃用 C++ AMP 标头。
包含任何 AMP 标头都会引发构建错误。 应在包含任何 AMP 标头之前定义 _SILENCE_AMP_DEPRECATION_WARNINGS,以使警告静音。
性能注意事项
如果使用 Visual C++ 组件扩展 C++/CX 创建通用 Windows 平台(UWP)应用,建议将纯旧数据(POD)类型与连续存储(例如 std::vector ,或 C 样式数组)一起使用,以用于 C++ AMP 的数据。 这可以帮助你实现比使用非 POD 类型或 Windows 运行时容器更高的性能,因为无需进行封送处理。
在 C++ AMP 内核中,若要访问以这种方式存储的数据,只需将std::vector或数组存储包裹在concurrency::array_view中,然后在concurrency::parallel_for_each循环中使用数组视图:
// simple vector addition example
std::vector<int> data0(1024, 1);
std::vector<int> data1(1024, 2);
std::vector<int> data_out(data0.size(), 0);
concurrency::array_view<int, 1> av0(data0.size(), data0);
concurrency::array_view<int, 1> av1(data1.size(), data1);
concurrency::array_view<int, 1> av2(data_out.size(), data2);
av2.discard_data();
concurrency::parallel_for_each(av0.extent, [=](concurrency::index<1> idx) restrict(amp)
{
av2[idx] = av0[idx] + av1[idx];
});
封送 Windows 运行时类型
使用 Windows 运行时 API 时,您可能希望对存储在 Windows 运行时容器(例如 Platform::Array<T>^)中的数据或使用 ref 关键字或 value 关键字声明的类或结构等复杂数据类型使用 C++ AMP。 在这些情况下,必须执行一些额外的工作,使数据可供 C++ AMP 使用。
Platform::Array<T>^,其中 T 是 POD 类型
当你遇到 Platform::Array<T>^ 且 T 是 POD 类型时,只需使用 get 成员函数即可访问其底层存储:
Platform::Array<float>^ arr; // Assume that this was returned by a Windows Runtime API
concurrency::array_view<float, 1> av(arr->Length, &arr->get(0));
如果 T 不是 POD 类型,请使用以下部分中介绍的技术将数据与 C++ AMP 配合使用。
Windows 运行时类型:ref 类和值类
C++ AMP 不支持复杂的数据类型。 这包括非 POD 类型和使用 ref 关键字或 值 关键字声明的任何类型。 如果在上下文中使用 restrict(amp) 了不支持的类型,则会生成编译时错误。
遇到不受支持的类型时,可以将其相关部分数据复制到对象 concurrency::array 中。 除了使数据可供 C++ AMP 使用之外,该手动复制方法还可以通过最大化数据局部性提高性能,并确保不会使用的数据不会被复制到加速器。 可以使用临时数组进一步提高性能,该 临时数组是一种特殊形式 concurrency::array ,它向 AMP 运行时提供提示,即应针对数组与指定加速器上的其他数组之间的频繁传输进行优化。
// pixel_color.h
ref class pixel_color sealed
{
public:
pixel_color(Platform::String^ color_name, int red, int green, int blue)
{
name = color_name;
r = red;
g = green;
b = blue;
}
property Platform::String^ name;
property int r;
property int g;
property int b;
};
// Some other file
std::vector<pixel_color^> pixels (256);
for (pixel_color ^pixel : pixels)
{
pixels.push_back(ref new pixel_color("blue", 0, 0, 255));
}
// Create the accelerators
auto cpuAccelerator = concurrency::accelerator(concurrency::accelerator::cpu_accelerator);
auto devAccelerator = concurrency::accelerator(concurrency::accelerator::default_accelerator);
// Create the staging arrays
concurrency::array<float, 1> red_vec(256, cpuAccelerator.default_view, devAccelerator.default_view);
concurrency::array<float, 1> blue_vec(256, cpuAccelerator.default_view, devAccelerator.default_view);
// Extract data from the complex array of structs into staging arrays.
concurrency::parallel_for(0, 256, [&](int i)
{
red_vec[i] = pixels[i]->r;
blue_vec[i] = pixels[i]->b;
});
// Array views are still used to copy data to the accelerator
concurrency::array_view<float, 1> av_red(red_vec);
concurrency::array_view<float, 1> av_blue(blue_vec);
// Change all pixels from blue to red.
concurrency::parallel_for_each(av_red.extent, [=](index<1> idx) restrict(amp)
{
av_red[idx] = 255;
av_blue[idx] = 0;
});