ユニバーサル Windows プラットフォーム (UWP) アプリで C++ AMP (C++ Accelerated Massive Parallelism) を使用して、GPU (グラフィックス処理装置) またはその他の計算アクセラレータで計算を実行できます。 ただし、C++ AMP には Windows ランタイム型を直接操作するための API は用意されておらず、Windows ランタイムには C++ AMP のラッパーが用意されていません。 自分で作成した型を含め、コードで Windows ランタイム型を使用する場合は、C++ AMP と互換性のある型に変換する必要があります。
注
C++ AMP ヘッダーは、Visual Studio 2022 バージョン 17.0 以降では非推奨です。
AMP ヘッダーを含めると、ビルド エラーが発生します。 警告をサイレント状態にするには、AMP ヘッダーを含める前に _SILENCE_AMP_DEPRECATION_WARNINGS を定義します。
パフォーマンスに関する考慮事項
Visual C++ コンポーネント拡張機能 C++/CX を使用してユニバーサル Windows プラットフォーム (UWP) アプリを作成する場合は、C++ AMP で使用されるデータに対して、 std::vector や C スタイルの配列などの連続したストレージと共に、プレーン古いデータ (POD) 型を使用することをお勧めします。 これは、マーシャリングを行う必要がないため、非 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 を使用する場合は、 Platform::Array<T>^ などの Windows ランタイム コンテナーに格納されているデータ、または 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 キーワードまたは value キーワードを使用して宣言された型が含まれます。 サポートされていない型が 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;
});