Share via


Gráficos (C++ AMP)

C++ AMP contiene varias API en el espacio de nombres Concurrency::graphics que se puede utilizar para tener acceso a la compatibilidad de textura en GPUs.Algunos escenarios comunes son los siguientes:

  • Se puede utilizar la clase textura como un contenedor de datos para el cálculo y aprovechar la localidad espacial de la caché de textura y de los diseños de hardware de la GPU.la localidad espacial es la propiedad de los datos que están físicamente cerca unos de otros.

  • El runtime proporciona interoperabilidad eficiente con los sombreadores que no computan.El píxel, el vértice, la teselación, y los sombreadores de casco con frecuencia consumen o generan texturas que puede utilizar en los cálculos de C++ AMP.

  • Los gráficos API en el C++ AMP proporcionan maneras alternativas de acceder a los búferes empaquetados de sub-palabras.Las texturas que tienen formatos que representan (elementos de textura) teselas se componen de escalares de 8 bits o de 16 bits, permiten el acceso a dicho almacén de datos empaquetado.

[!NOTA]

Las API de C++ AMP no proporcionan muestreo de textura ni funcionalidad de filtrado.Se deben utilizar las características de interoperabilidad de C++ AMP y luego escribir el código en DirectCompute y HLSL.

Los tipos norm y unorm

Los tipos norm y unorm son tipos escalares que limitan el rango de valores float ; esto se conoce como clamping.Estos tipos se pueden construir explícitamente a partir de otros tipos escalares.En las conversiones, el valor es la primera conversión a float y después se fija a la región correspondiente que el norm [- 1,0… 1,0] o el unorm [0,0… 1,0] permite.La conversión de +/- infinito devuelve +/-1.La conversión de NaN es indefinido.Un norm puede ser construido implícitamente a partir de un unorm y sin pérdida de datos.La conversión implícita del operador a float se define en los siguientes tipos.Los operadores binarios están definidos entre estos tipos y otros tipos escalares integrados como float e int: +, -, *,/, ==, !=, >, <, >=, <=.También admiten los operadores de asignación compuestos: +=, -=, *=,/=.El operador unario de negación (-) está definido para los tipos norm.

Biblioteca de vector corto.

La biblioteca de vector corto proporciona algunas de las funcionalidades de Tipo de vector que se define en HLSL y se utiliza normalmente para definir los téxeles.Un vector corto es una estructura de datos que contiene de uno a cuatro valores del mismo tipo.Los tipos admitidos son double, float, int, norm, uint y unorm.Los nombres de los tipos se muestran en la siguiente tabla.Para cada tipo, también hay un typedef correspondiente que no lleva un subrayado en el nombre.Los tipos que llevan subrayado están en Concurrency::graphics (Espacio de nombres).Los tipos que no llevan subrayado están en Concurrency::graphics::direct3d (Espacio de nombres) y están claramente separados de los tipos fundamentales denominados de forma similar,tales como __int8 y __int16.

Longitud 2

Longitud 3

Longitud 4

double

double_2

double2

double_3

double3

double_4

double4

float

float_2

float2

float_3

float3

float_4

float4

Valor int.

int_2

int2

int_3

int3

int_4

int4

norm

norm_2

norm2

norm_3

norm3

norm_4

norm4

uint

uint_2

uint2

uint_3

uint3

uint_4

uint4

unorm

unorm_2

unorm2

unorm_3

unorm3

unorm_4

unorm4

Hh913015.collapse_all(es-es,VS.110).gifOperadores

Si se define un operador entre dos vectores cortos, entonces se define también entre un vector corto y uno escalar.Además, uno de ellos debe ser true:

  • El tipo escalar tiene que ser igual que el tipo de elemento del vector corto.

  • El tipo escalar se puede convertir implícitamente en el tipo de elemento del vector utilizando únicamente una conversión definida por el usuario.

La operación se lleva a cabo entre cada componente del vector corto y el escalar.Los operadores válidos son:

Tipo operador

Tipos válidos

Operadores binarios

Válido en todos los tipos: +, -, *, /,

Válido en tipos enteros: %, ^, |, &, <<, >>

Los dos vectores deben tener el mismo tamaño y el resultado es un vector del mismo tamaño.

Operadores relacionales

Válido en todos los tipos: == y !=

Operador de asignación compuesto

Válido en todos los tipos: +=, -=, *=, /=

Válido en tipos enteros: %=, ^=, |=, &=, <<=, >>=

Operadores de incremento y decremento

Válido en todos los tipos: ++, --

Tanto el prefijo como el sufijo son válidos.

Operador NOT bit a bit (~)

Válido en tipos enteros.

Operador unario -

Válido en todos los tipos excepto unorm y uint.

Hh913015.collapse_all(es-es,VS.110).gifExpresiones swizzling

La biblioteca de vector corto admite el concepto del descriptor de acceso vector_type.identifier para acceder a los componentes de un vector corto.El identifier, conocido como expresión swizzling, especifica los componentes del vector.La expresión puede ser un valor l o un valor r.Los caracteres individuales del identificador pueden ser: x, y, z, y w; o r, g, b y a.«x» y «r» significan el componente zeroésimo, «y» y «g» significan el primer componente y así sucesivamente.(Observe que «x» y «r» no se pueden utilizar en el mismo identificador.) Por consiguiente, «rgba» y «xyzw» devuelven el mismo resultado.Los descriptores de acceso de un único componente como «x» e «y» son tipos de valores escalares.Los descriptores de varios componentes son tipos de vector corto.Por ejemplo, si crea un vector int_4 denominado fourInts y tiene los valores 2, 4, 6 y 8, entonces fourInts.y devuelve el entero 4 y fourInts.rg devuelve un objeto de int_2 con los valores 2 y 4.

Clases de Texturas

Muchas GPU tienen hardware y cachés que se optimizan para capturar los pixels y las téxeles y ofrecer imágenes y texturas.La clase textura<T,N> , que es una clase contenedora para los objetos de téxeles, expone la funcionalidad de textura de los GPU.Una téxel puede ser:

  • Un int, uint, float, double, norm o un escalar unorm.

  • Un vector corto que tiene dos o cuatro componentes.La única excepción es double_4, que no se permite.

El objeto texture puede tener un rango de 1, 2, 3.El objeto texture se puede capturar solamente por referencia en la expresión lambda de una llamada a parallel_for_each.Los téxeles se almacenan en la GPU como objetos de textura Direct3D.Para obtener más información sobre texturas y téxeles en Direct3d, consulte introducción a las texturas en Direct3D 11.

El tipo de téxel que se usa puede ser uno de los muchos formatos de textura que se utilizan en la programación de gráficos.Por ejemplo, un formato RGBA podría utilizar 32 bits, con 8 bits para cada uno de los elementos escalares R, G, B y A.El hardware de textura de una tarjeta gráfica puede acceder a los elementos individuales basados en el formato.Por ejemplo, si se utiliza el formato RGBA, el hardware de textura puede convertir cada elemento de 8 bits en un formulario de 32 bits.En C++ AMP, se pueden establecer los bits por elemento escalar del téxel y así para poder automáticamente tener acceso a los elementos escalares individuales en el código sin utilizar el desplazamiento de bit.

Hh913015.collapse_all(es-es,VS.110).gifCreación de instancias de objetos de textura

Se puede declarar un objeto de textura sin inicialización.El siguiente ejemplo de código declara varios objetos de textura.

#include <amp.h>
#include <amp_graphics.h>
using namespace concurrency;
using namespace concurrency::graphics;

void declareTextures() {

    // Create a 16-texel texture of int. 
    texture<int, 1> intTexture1(16);  
    texture<int, 1> intTexture2(extent<1>(16)); 

    // Create a 16 x 32 texture of float_2.  
    texture<float_2, 2> floatTexture1(16, 32);  
    texture<float_2, 2> floatTexture2(extent<2>(16, 32));   

    // Create a 2 x 4 x 8 texture of uint_4. 
    texture<uint_4, 3> uintTexture1(2, 4, 8);  
    texture<uint_4, 3> uintTexture2(extent<3>(2, 4, 8));
}

También se puede utilizar un constructor para declarar e inicializar un objeto texture.El siguiente ejemplo de código crea una instancia de un objeto texture desde un vector de objetos float_4.Los bits por elemento escalar se establecen en el valor predeterminado.No se puede utilizar este constructor con norm, unorm o los vectores cortos de norm y de unorm, porque no tienen bits predeterminados para el elemento escalar.

#include <amp.h>
#include <amp_graphics.h>
#include <vector>
using namespace concurrency;
using namespace concurrency::graphics;

void initializeTexture() {

    std::vector<int_4> texels;
    for (int i = 0; i < 768 * 1024; i++) {
        int_4 i4(i, i, i, i);
        texels.push_back(i4);
    }
    
texture<int_4, 2> aTexture(768, 1024, texels.begin(), texels.end());
}

También se puede declarar e inicializar un objeto texture mediante una sobrecarga del constructor que tome un puntero a los datos de origen, el tamaño de los datos de origen en bytes y los bits por elemento escalar.

void createTextureWithBPC() {
    // Create the source data.
    float source[1024 * 2]; 
    for (int i = 0; i < 1024 * 2; i++) {
        source[i] = (float)i;
    }

    // Initialize the texture by using the size of source in bytes
    // and bits per scalar element.
    texture<float_2, 1> floatTexture(1024, source, (unsigned int)sizeof(source), 32U); 
}

Las texturas en estos ejemplos se crean en la vista predeterminada del acelerador predeterminado.Se pueden utilizar otras sobrecargas del constructor si desea especificar un objeto accelerator_view.No se puede crear un objeto de textura en un acelerador de CPU.

Hay límites respecto al tamaño de cada dimensión del objeto texture, como se muestra en la siguiente tabla.Se genera un error en tiempo de ejecución si se superan los límites.

Textura

Limitación de tamaño

textura<T,1>

16384

textura<T,2>

16384

textura<T,2>

2048

Hh913015.collapse_all(es-es,VS.110).gifLectura desde objetos de textura

Se puede leer un objeto texture mediante texture::operator[] (Operador), texture::operator() (Operador) o texture::get (Método).texture::operator[] (Operador) y texture::operator() (Operador) devuelven un valor, no una referencia.Por consiguiente, no se puede escribir a un objeto texture mediante texture::operator[] (Operador).

void readTexture() {
    std::vector<int_2> src;    
    for (int i = 0; i < 16 *32; i++) {
        int_2 i2(i, i);
        src.push_back(i2);
    }

    std::vector<int_2> dst(16 * 32);  
    array_view<int_2, 2> arr(16, 32, dst);  
    arr.discard_data(); 

    const texture<int_2, 2> tex9(16, 32, src.begin(), src.end());  
    parallel_for_each(tex9.extent, [=, &tex9] (index<2> idx) restrict(amp) {          
        // Use the subscript operator.      
        arr[idx].x += tex9[idx].x; 
        // Use the function () operator.      
        arr[idx].x += tex9(idx).x; 
        // Use the get method.
        arr[idx].y += tex9.get(idx).y; 
        // Use the function () operator.  
        arr[idx].y += tex9(idx[0], idx[1]).y; 
    });  

    arr.synchronize();
}

El siguiente ejemplo de código muestra cómo almacenar los canales de textura en un vector corto y después tener acceso a los elementos escalares individuales como propiedades del vector corto.

void UseBitsPerScalarElement() {
    // Create the image data. 
    // Each unsigned int (32-bit) represents four 8-bit scalar elements(r,g,b,a values).
    const int image_height = 16;
    const int image_width = 16;
    std::vector<unsigned int> image(image_height * image_width);

    extent<2> image_extent(image_height, image_width);

    // By using uint_4 and 8 bits per channel, each 8-bit channel in the data source is 
    // stored in one 32-bit component of a uint_4.
    texture<uint_4, 2> image_texture(image_extent, image.data(), image_extent.size() * 4U,  8U);

    // Use can access the RGBA values of the source data by using swizzling expressions of the uint_4.
    parallel_for_each(image_extent,  
         [&image_texture](index<2> idx) restrict(amp) 
    { 
        // 4 bytes are automatically extracted when reading.
        uint_4 color = image_texture[idx]; 
        unsigned int r = color.r; 
        unsigned int g = color.g; 
        unsigned int b = color.b; 
        unsigned int a = color.a; 
    });
}

En la siguiente tabla se enumeran los bits válidos por canal para cada tipo de vector.

Tipo de datos de textura

Bits válidos por elemento escalar

int, int_2, int_4

uint, uint_2, uint_4

8, 16, 32

float, float_2, float_4

16, 32

double, double_2

64

norm, norm_2, norm_4

unorm, unorm_2, unorm, 4

8, 16

Hh913015.collapse_all(es-es,VS.110).gifEscritura en los objetos de textura

Utilice el método texture::set para escribir en los objetos texture.Un objeto de textura puede ser de sólo lectura o de lectura y escritura.Para que un objeto de textura sea legible y grabable, las siguientes condiciones deben ser verdaderas:

  • T tiene sólo un componente escalar.(Los vectores cortos no se permiten.)

  • T no es double, norm o unorm.

  • La propiedad texture::bits_per_scalar_element es 32.

Si los tres no son true, el objeto texture es de sólo lectura.Las dos primeras condiciones se comprueban durante la compilación.Se genera un error de compilación si se tiene código que intenta escribir en objeto textura a readonly.La condición para texture::bits_per_scalar_element se detecta en tiempo de ejecución y el runtime genera una excepción unsupported_feature si se intenta escribir en un objeto de solo lectura en texture.

El siguiente ejemplo de código escribe valores en un objeto textura.

void writeTexture() {
    texture<int, 1> tex1(16); 
    parallel_for_each(tex1.extent, [&tex1] (index<1> idx) restrict(amp) {    
        tex1.set(idx, 0); 
    });

}

Hh913015.collapse_all(es-es,VS.110).gifUtilización de un objeto writeonly_texture_view

La clase writeonly_texture_view proporciona una vista de solo escritura de un objeto de textura.El objeto writeonly_texture_view debe ser capturado por el valor de la expresión lambda.El siguiente ejemplo de código utiliza un objeto writeonly_texture_view para escribir en el objeto texture con dos componentes (int_2).

void write2ComponentTexture() {
    texture<int_2, 1> tex4(16); 
    writeonly_texture_view<int_2, 1> wo_tv4(tex4); 
    parallel_for_each(extent<1>(16), [=] (index<1> idx) restrict(amp) {   
        wo_tv4.set(idx, int_2(1, 1)); 
    });
}

Hh913015.collapse_all(es-es,VS.110).gifCopiado de objetos de textura

Se puede copiar entre los objetos de textura mediante la función copy o la función copy_async, como se muestra en el siguiente ejemplo de código.

void copyHostArrayToTexture() {
    // Copy from source array to texture object by using the copy function.
    float floatSource[1024 * 2]; 
    for (int i = 0; i < 1024 * 2; i++) {
        floatSource[i] = (float)i;
}
    texture<float_2, 1> floatTexture(1024);
    copy(floatSource, (unsigned int)sizeof(floatSource), floatTexture); 

    // Copy from source array to texture object by using the copy function.
    char charSource[16 * 16]; 
    for (int i = 0; i < 16 * 16; i++) {
        charSource[i] = (char)i;
    }
    texture<int, 2> charTexture(16, 16, 8U);
    copy(charSource, (unsigned int)sizeof(charSource), charTexture); 
    // Copy from texture object to source array by using the copy function.
    copy(charTexture, charSource, (unsigned int)sizeof(charSource)); 
}

También se puede copiar desde una textura a otra mediante el método texture::copy_to.Las dos texturas pueden estar en diferentes accelerator_views.Cuando se copia en un objeto writeonly_texture_view, los datos se copian en el objeto subyacente texture.Los bits por elemento escalar y la extensión deben ser iguales en los objetos de texture de origen y de destino.Si los requisitos no se cumplen, el runtime produce una excepción.

Interoperabilidad

El runtime de C++ AMP admite la interoperabilidad entre texture<T,1> y la interfaz de ID3D11Texture1D, entre texture<T,2> y la interfaz de ID3D11Texture2D y entre texture<T,3> y la interfaz de ID3D11Texture3D.El método get_texture toma un objeto texture y devuelve una interfaz IUnknown.El método make_texture toma una interfaz IUnknown y un objeto accelerator_view y devuelve un objeto texture.

Vea también

Referencia

double_2 (Clase)

double_3 (Clase)

double_4 (Clase)

float_2 (Clase)

float_3 (Clase)

float_4 (Clase)

int_2 (Clase)

int_3 (Clase)

int_4 (Clase)

norm_2 (Clase)

norm_3 (Clase)

norm_4 (Clase)

short_vector (Estructura)

short_vector_traits (Estructura)

uint_2 (Clase)

uint_3 (Clase)

uint_4 (Clase)

unorm_2 (Clase)

unorm_3 (Clase)

unorm_4 (Clase)