Uso de C++ AMP en aplicaciones para UWP

Puede usar C++ AMP (C++ Accelerated Massive Parallelism) en la aplicación de la Plataforma universal de Windows (UWP) para realizar cálculos en la GPU (unidad de procesamiento de gráficos) u otros aceleradores de cálculo. Sin embargo, C++ AMP no proporciona las API para trabajar directamente con los tipos de Windows Runtime y este no proporciona un contenedor para C++ AMP. Cuando use los tipos de Windows Runtime en el código, incluidos los que ha creado usted mismo, debe convertirlos en tipos compatibles con C++ AMP.

Nota:

Los encabezados de C++ AMP están en desuso a partir de la versión 17.0 de Visual Studio 2022. Si se incluyen encabezados AMP, se generarán errores de compilación. Defina _SILENCE_AMP_DEPRECATION_WARNINGS antes de incluir encabezados AMP para silenciar las advertencias.

Consideraciones de rendimiento

Si usa extensiones de componentes de Visual C++ para crear la aplicación de la Plataforma universal de Windows (UWP), recomendamos utilizar tipos de datos antiguos sin formato (POD) junto con almacenamiento contiguo; por ejemplo, std::vector o matrices del estilo C para los datos que se usarán con C++ AMP. Esto puede ayudarle a lograr un mayor rendimiento que mediante el uso de tipos que no son POD o contenedores de Windows Runtime porque no se tiene que producir ninguna serialización.

En un kernel de C++ AMP, para acceder a los datos almacenados de esta manera, simplemente encapsula el almacenamiento de matriz std::vector o en y concurrency::array_view , a continuación, use la vista de matriz en un concurrency::parallel_for_each bucle:

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

Calcular referencias de tipos de Windows en tiempo de ejecución

Al trabajar con las API de Windows Runtime, puede usar C++ AMP en los datos almacenados en un contenedor de Windows Runtime como Platform::Array<T>^ o en tipos de datos complejos como clases o estructuras que se declaran con la palabra clave ref o la palabra clave valor. En estas situaciones, tiene que realizar alguna tarea adicional para que los datos estén disponibles para C++ AMP.

Platform::Array<T>^, donde T es un tipo POD

Cuando encuentra un contenedor Platform::Array<T>^ y T es un tipo POD, puede tener acceso al almacén subyacente simplemente usando la función miembro 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));

Si T no es un tipo POD, use la técnica que se describe en la sección siguiente para utilizar los datos con C++ AMP.

Tipos de Windows Runtime: clases de referencia y clases de valor

C++ AMP no admite tipos de datos complejos. Esto incluye los tipos que no sean POD y cualquier tipo que se declare con la palabra clave ref o la palabra clave valor. Si se usa un tipo no compatible en un contexto restrict(amp), se genera un error en tiempo de compilación.

Si encuentra un tipo no compatible, puede copiar elementos interesantes de sus datos en un objeto concurrency::array. Además de conseguir que los datos estén disponibles para su uso por parte de C++ AMP, este enfoque de copia manual también puede mejorar el rendimiento maximizando la situación de los datos y garantizando que los datos que no se usen no se copiarán en el acelerador. Puede mejorar aún más el rendimiento usando una matriz de almacenamiento provisional, que es una forma especial de concurrency::array. Esta sugiere al runtime de AMP que la matriz se debería optimizar para las transferencias frecuentes entre ella y otras matrices del 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;
    });

Consulte también

Crear su primera aplicación para UWP con C++
Crear componentes de Windows Runtime en C++