UWP 앱에서 C++ AMP 사용
UWP(유니버설 Windows 플랫폼) 앱에서 C++ AMP(C++ 가속 대규모 병렬 처리)를 사용하여 GPU(그래픽 처리 장치) 또는 기타 계산 가속기에서 계산을 수행할 수 있습니다. 그러나, C++ AMP는 Windows Runtime 형식으로 직접 작업하기 위한 API를 제공하지 않으며, Windows 런타임은 C++ AMP에 대한 래퍼를 제공하지 않습니다. 코드(본인이 직접 만든 형식 포함)에 Windows 런타임 형식을 사용할 경우 C++ AMP와 호환되는 형식으로 변환해야 합니다.
참고 항목
C++ AMP 헤더는 Visual Studio 2022 버전 17.0부터 더 이상 사용되지 않습니다.
AMP 헤더를 포함하면 빌드 오류가 생성됩니다. 경고를 무음으로 표시하기 위해 AMP 헤더를 포함하기 전에 정의 _SILENCE_AMP_DEPRECATION_WARNINGS
합니다.
성능 고려 사항
Visual C++ 구성 요소 확장 C++/CX를 사용하여 UWP(유니버설 Windows 플랫폼) 앱을 만드는 경우 C++ AMP와 함께 사용할 데이터에 대해 연속 스토리지(예std::vector
: C 스타일 배열)와 함께 POD(일반 데이터) 형식을 사용하는 것이 좋습니다. 이렇게 하면 마샬링이 발생하지 않으므로 비 POD 형식 또는 Windows 런타임 컨테이너를 사용하는 것보다 더 높은 성능을 얻을 수 있습니다.
C++ AMP 커널에서 이러한 방식으로 저장된 데이터에 액세스하려면 배열 스토리지를 래 concurrency::array_view
핑 std::vector
한 다음 루프에서 배열 뷰를 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를 사용하는 경우 ref 키워드(keyword) 또는 키워드(keyword) 값을 사용하여 선언된 클래스 또는 구조체와 같은 복잡한 데이터 형식과 Platform::Array<T>^
같은 Windows 런타임 컨테이너에 저장된 데이터에 C++ AMP를 사용할 수 있습니다. 이러한 상황에서는 C++ AMP에서 데이터를 사용할 수 있도록 몇 가지 추가 작업을 수행해야 합니다.
Platform::Array<T>^, 여기서 T는 POD 형식입니다.
T가 Platform::Array<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 키워드(keyword) 또는 키워드(keyword) 값을 사용하여 선언된 모든 형식이 포함됩니다. 지원되지 않는 형식이 컨텍스트에서 restrict(amp)
사용되는 경우 컴파일 시간 오류가 생성됩니다.
지원되지 않는 형식이 발견되면 데이터의 흥미로운 부분을 개체에 복사할 concurrency::array
수 있습니다. 이 수동 복사 방법은 C++ AMP에서 데이터를 사용할 수 있도록 하는 것 외에도 데이터 지역성을 최대화하고 사용되지 않는 데이터가 가속기로 복사되지 않도록 하여 성능을 향상시킬 수 있습니다. 지정된 액셀러레이터에서 배열과 다른 배열 간의 빈번한 전송을 위해 배열을 최적화해야 한다는 힌트를 AMP 런타임에 제공하는 특별한 형식인 concurrency::array
스테이징 배열을 사용하여 성능을 더욱 향상시킬 수 있습니다.
// 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;
});