Condividi tramite


Uso di C++ AMP in app UWP

Puoi usare C++ AMP (C++ Accelerated Massive Parallelism) nella tua app piattaforma UWP (Universal Windows Platform) (UWP) per eseguire calcoli sulla GPU (Unità di elaborazione grafica) o su altri acceleratori di calcolo. Tuttavia, C++ AMP non fornisce API per utilizzare direttamente i tipi Windows Runtime; inoltre, Windows Runtime non fornisce un wrapper per C++ AMP. Quando si utilizzano i tipi Windows Runtime nel codice, inclusi quelli creati dall'utente, è necessario convertirli in tipi compatibili con C++ AMP.

Nota

Le intestazioni C++ AMP sono deprecate a partire da Visual Studio 2022 versione 17.0. L'inclusione di eventuali intestazioni AMP genererà errori di compilazione. Definire _SILENCE_AMP_DEPRECATION_WARNINGS prima di includere eventuali intestazioni AMP per disattivare gli avvisi.

Considerazioni sulle prestazioni

Se usi le estensioni del componente Visual C++ C++/CX per creare la tua app piattaforma UWP (Universal Windows Platform) (UWP), ti consigliamo di usare i tipi POD (Plain-Old-Data) insieme all'archiviazione contigua, std::vector ad esempio o matrici in stile C, per i dati che verranno usati con C++ AMP. Ciò consente di ottenere prestazioni più elevate rispetto all'uso di tipi non POD o contenitori di Windows Runtime perché non è necessario eseguire il marshalling.

In un kernel C++ AMP, per accedere ai dati archiviati in questo modo, è sufficiente eseguire il wrapping dell'archiviazione std::vector o della matrice in un concurrency::array_view e quindi usare la visualizzazione matrice in un concurrency::parallel_for_each ciclo:

// 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];
    });

Marshalling dei tipi di Windows Runtime

Quando si usano le API di Windows Runtime, è possibile usare C++ AMP sui dati archiviati in un contenitore windows Runtime, ad esempio un Platform::Array<T>^ o in tipi di dati complessi, ad esempio classi o struct dichiarati usando la parola chiave ref o la parola chiave value . In queste situazioni, è necessario eseguire alcune operazioni aggiuntive per rendere i dati disponibili per C++ AMP.

Platform::Array<T>^, dove T è un tipo POD

Quando si rileva un Platform::Array<T>^ e T è un tipo POD, è possibile accedere alla risorsa di archiviazione sottostante usando solo la get funzione membro:

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 non è un tipo POD, usare la tecnica descritta nella sezione seguente per usare i dati con C++ AMP.

Tipi di Windows Runtime: classi di riferimento e classi di valore

C++ AMP non supporta tipi di dati complessi. Sono inclusi i tipi non POD e tutti i tipi dichiarati usando la parola chiave ref o la parola chiave value . Se in un contesto viene usato un restrict(amp) tipo non supportato, viene generato un errore in fase di compilazione.

Quando si verifica un tipo non supportato, è possibile copiare parti interessanti dei dati in un concurrency::array oggetto . Oltre a rendere disponibili i dati per C++ AMP da utilizzare, questo approccio di copia manuale può anche migliorare le prestazioni ottimizzando la località dei dati e assicurandosi che i dati che non verranno usati non vengano copiati nell'acceleratore. È possibile migliorare ulteriormente le prestazioni usando una matrice di staging, una forma speciale di concurrency::array che fornisce un suggerimento al runtime AMP che la matrice deve essere ottimizzata per il trasferimento frequente tra di esso e altre matrici sull'acceleratore specificato.

// 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;
    });

Vedi anche

Creare la prima app UWP con C++
Creazione di componenti Windows Runtime in C++