Usar o C++ AMP em aplicativos UWP
Você pode usar C++ AMP (C++ Accelerated Massive Parallelism) em seu aplicativo da Plataforma Universal do Windows (UWP) para executar cálculos na GPU (unidade de processamento gráfico) ou em outros aceleradores computacionais. No entanto, o C++ AMP não fornece APIs para trabalhar diretamente com tipos do Windows Runtime, e o Windows Runtime não fornece um wrapper para C++ AMP. Ao usar tipos do Windows Runtime em seu código, incluindo aqueles que você mesmo criou, você deve convertê-los em tipos compatíveis com o C++ AMP.
Observação
Os cabeçalhos AMP C++ foram preteridos a partir do Visual Studio 2022 versão 17.0.
Incluir todos os cabeçalhos AMP gerará erros de build. Defina _SILENCE_AMP_DEPRECATION_WARNINGS
antes de incluir qualquer cabeçalho AMP para silenciar os avisos.
Considerações sobre o desempenho
Se você estiver usando as extensões de componente do Visual C++ C++/CX para criar seu aplicativo de Plataforma Universal do Windows (UWP), recomendamos que você use tipos POD (dados antigos simples) junto com o armazenamento contíguo, por exemplo, std::vector
ou matrizes de estilo C, para dados que serão usados com o C++ AMP. Isso pode ajudá-lo a obter um desempenho mais alto do que usando tipos não-POD ou contêineres do Tempo de Execução do Windows, pois não é necessário que ocorra empacotamento.
Em um kernel AMP C++, para acessar os dados armazenados dessa maneira, basta encapsular o armazenamento de std::vector
matriz em um e usar a exibição de matriz em um concurrency::array_view
concurrency::parallel_for_each
loop:
// 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];
});
Marshaling tipos de Windows Runtime
Ao trabalhar com APIs do Windows Runtime, convém usar C++ AMP em dados armazenados em um contêiner do Windows Runtime, como uma Platform::Array<T>^
, ou em tipos de dados complexos, como classes ou structs declarados usando a palavra-chave ref ou a palavra-chave value. Nessas situações, você precisa fazer um trabalho extra para disponibilizar os dados para o C++ AMP.
Platform::Array<T>^, em que T é um tipo POD
Quando você encontra uma Platform::Array<T>^
e T é um tipo POD, você pode acessar o armazenamento subjacente apenas usando a função membro 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));
Se T não for um tipo POD, use a técnica descrita na seção a seguir para usar os dados com o C++ AMP.
Tipos de Windows Runtime: classes ref e value
O C++ AMP não dá suporte a tipos de dados complexos. Isso inclui tipos não POD e todos os tipos declarados usando a palavra-chave ref ou a palavra-chave value. Se um tipo sem suporte for usado em um contexto restrict(amp)
, será gerado um erro de tempo de compilação.
Ao encontrar um tipo sem suporte, você pode copiar partes interessantes de seus dados em um objeto concurrency::array
. Além de disponibilizar os dados para consumo pelo C++ AMP, essa abordagem de cópia manual também pode melhorar o desempenho maximizando a localidade dos dados e garantindo que os dados que não serão usados não serão copiados para o acelerador. Você pode melhorar ainda mais o desempenho usando uma matriz de preparo, uma forma especial de concurrency::array
que fornece uma dica para o runtime AMP de que a matriz deve ser otimizada para transferência frequente entre ela e outras matrizes no acelerador especificado.
// 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;
});
Confira também
Criar seu primeiro aplicativo UWP usando C++
Criando componentes do Windows Runtime no C++