Partilhar via


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_viewconcurrency::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++