Partager via


Graphiques (C++ AMP)

C++ AMP contient plusieurs APIs dans l'espace de noms Concurrency::graphics que vous pouvez utiliser pour accéder à la prise en charge des textures sur GPUs.Parmi les scénarios courants figurent :

  • Vous pouvez utiliser la classe Texture comme un conteneur de données pour le calcul et l'exploitation de la localité spatiale du cache de texture et des layouts du matériel GPU.La localité spatiale est la propriété des éléments de données physiquement à proximité les uns des autres.

  • Le runtime fournit une interopérabilité efficace avec des shaders non calculés.Les pixel shaders, vertex shaders, tessellation shaders, et hull shaders consomment ou produisent fréquemment des textures utilisables dans les calculs C++ AMP.

  • Les APIs graphiques de C++ AMP fournissent des moyens alternatifs pour accéder aux mémoires tampons contenant des sous-mots.Les textures formatées sous forme de texels (éléments de texture) qui sont composées de scalaires de 8 bits ou 16 bits permettent l'accès à un tel stock des données compressé.

[!REMARQUE]

Les APIs C++ AMP ne fournissent pas l'échantillonnage de texture ni le filtrage.Vous devez utiliser les fonctionnalités d'interopérabilité de C++ AMP puis écrire le code dans DirectCompute et HLSL.

Les types norm et unorm

Les types norm et unorm sont des types scalaires qui limitent la gamme de valeurs float; ce concept est appelé le clamping.Ces types peuvent être explicitement construits à partir d'autres types scalaires.Dans un casting, la valeur est premièrement castée en float puis fixée à la zone respective autorisée par norm [-1,0…1,0] ou unorm [0,0…1,0].Le cast de +/- infini retourne +/-1.Le cast depuis NaN n'est pas défini.Un norm peut être implicitement construit à partir d'un unorm et il n'y a pas de perte de données.L'opérateur de conversion implicite en float est défini sur ces types.Les opérateurs binaires sont définis entre ces types et d'autres types scalaires intégrés tels que float et int: +, -, *, /, ==, !=, >, <, >=, <=.Les opérateurs d'affectation composée sont également pris en charge: +=, -=, *=, /=.L'opérateur de négation unaire (-) est défini pour les types norm.

Bibliothèque de vecteurs courts

La bibliothèque de vecteurs courts fournit une partie des fonctionnalités du Vector Type défini dans HLSL et est généralement utilisé pour définir des texels.Un vecteur court est une structure de données contenant une à quatre valeurs du même type.Les types pris en charge sont double, float, int, norm, uint, et unorm.Les noms des types sont affichés dans le tableau suivant.Pour chaque type, il existe également un typedef correspondant n'ayant pas d'underscore dans son nom.Les types ayant des underscores se trouvent dans Concurrency::graphics, espace de noms.Les types n'ayant pas d'underscores se trouvent dans Concurrency::graphics::direct3d, espace de noms afin qu'ils soient clairement séparés des types fondamentaux nommés de façon similaire comme __int8 et __int16.

Longueur 2

Longueur 3

Longueur 4

double

double_2

double2

double_3

double3

double_4

double4

float

float_2

float2

float_3

float3

float_4

float4

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(fr-fr,VS.110).gifOpérateurs

Si un opérateur est défini entre deux vecteurs courts, alors il est également défini entre un vecteur court et un scalaire.De plus, l'une d'elles doit être vraie:

  • Le type du scalaire doit être identique au type d'élément du vecteur court.

  • Le type du scalaire peut être implicitement converti vers le type d'élément du vecteur à l'aide d'une seule conversion définie par l'utilisateur.

L'opération est portée entre chaque composant du vecteur court et la variable scalaire.Voici les opérateurs valides:

Type d'opérateur

Types valides

Opérateurs binaires

Valide sur tous les types: +, -, *, /,

Valide sur les types d'entiers: %, ^, |, &, <<, >>

Les deux vecteurs doivent avoir la même taille, et le résultat est un vecteur de la même taille.

Opérateurs relationnels

Valide sur tous les types: == et !=

Opérateur d'affectation composée

Valide sur tous les types: +=, -=, *=, /=

Valide sur les types d'entiers: %=, ^=, |=, &=, <<=, >>=

Opérateurs d'incrémentation et de décrémentation

Valide sur tous les types: ++, --

Le préfixe et le suffixe sont valides.

Opérateur bitwise NOT (~)

Valide sur les types d'entiers.

Opérateur unaire -

Valide sur tous les types hormis unorm et uint.

Hh913015.collapse_all(fr-fr,VS.110).gifExpressions de swizzling

La bibliothèque de vecteurs courts prend en charge la construction de l'accesseur vector_type.identifier pour accéder aux composants d'un vecteur court.L' identifier, aussi appelé expression de swizzling, spécifie les composants du vecteur.L'expression peut être une l-value ou une r-value.Les différents caractères de l'identificateur peuvent être: x, y, z, et w; ou r, g, b, et a. "x" et " r" représentent le composant de zéro, "y" et "g" représentent le premier composant, et ainsi de suite.(Notez que "x" et "r" ne peuvent être utilisés dans le même identifier.) Par conséquent, "rgba" et "xyzw" retournent le même résultat.Les accesseurs à un composant tels que "x" et "y" sont des types de valeur scalaire.Les accesseurs à plusieurs composants sont des types de vecteurs courts.Par exemple, si vous construisez un vecteur int_4 nommé fourInts et ayant les valeurs 2, 4, 6, et 8, alors fourInts.y retourne l'entier 4 fourInts.rg retourne un objet int_2 ayant les valeurs 2 et 4.

Classes de texture

De nombreux GPU ont un matériel et des caches optimisées pour récupérer des pixels et des texels afin d'afficher des images et des textures.La classe texture<T,N>, qui est une classe de conteneur pour objets texel, expose la fonctionnalitée de texture de ces GPUs.Un texel peut être:

  • Un scalaire de type int, uint, float, double, norm, ou unorm.

  • Un vecteur court ayant deux ou quatre composants.La seule exception est double_4, qui n'est pas autorisée.

L'objet texture peut avoir un rang de 1, 2, ou 3.L'objet texture peut être capturé uniquement par référence dans le lambda d'un appel à parallel_for_each.La texture est stockée sur le GPU en tant qu'objet de texture Direct3D.Pour plus d'informations sur les textures et des texels dans Direct3d, consultez Introduction aux textures dans Direct3D 11.

Le type de texel que vous utilisez peut être l'un des nombreux formats de texture utilisés dans la programmation graphique.Par exemple, un format de RVBA peut utiliser 32 bits, avec 8 bits pour chacun des éléments scalaires R, G, B, et A.Le matériel de texture d'une carte graphique peut accéder aux éléments individuels selon leur format.Par exemple, si vous utilisez le format RVBA, le matériel de texture peut extraire chaque élément 8 bits dans une forme 32 bits.En C++ AMP, vous pouvez définir des bits par élément scalaire de votre texel afin d'accéder automatiquement aux éléments scalaires individuels dans le code sans utiliser le décalage de bits.

Hh913015.collapse_all(fr-fr,VS.110).gifInstanciation d'objets Texture

Vous pouvez déclarer un objet de texture sans l'initialiser.L'exemple de code suivant déclare plusieurs objets de texture.

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

Vous pouvez également utiliser un constructeur pour déclarer et initialiser un objet texture.L'exemple de code suivant instancie un objet texture à partir d'un vecteur d'objets float_4.Les bits par élément scalaire sont définis à la valeur par défaut.Vous ne pouvez pas utiliser ce constructeur avec norm, unorm, ou les vecteurs courts de norm et de unorm, car ils n'ont pas de bits par défaut par élément scalaire.

#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());
}

Vous pouvez également déclarer et initialiser un objet texture à l'aide d'une surcharge de constructeur prenant un pointeur vers les données sources, la taille en octets des données sources, et les bits par élément scalaire.

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

Les textures dans ces exemples sont créées sur la vue par défaut de l'accélérateur par défaut.Vous pouvez utiliser d'autres surcharges du constructeur si vous souhaitez spécifier un objet accelerator_view.Vous ne pouvez pas créer un objet de texture sur un accélérateur CPU.

Il existe des limites sur la taille de chaque dimension de l'objet texture, comme l'indique le tableau suivant.Une erreur d'exécution est générée si vous dépassez les limites.

Texture

Limitation de taille

texture<T,1>

16384

texture<T,2>

16384

texture<T,2>

2048

Hh913015.collapse_all(fr-fr,VS.110).gifLecture des objets de texture

Vous pouvez lire un objet texture à l'aide de texture::operator[], opérateur, de texture::operator(), opérateur, ou de texture::get, méthode.texture::operator[], opérateur et texture::operator(), opérateur retournent une valeur, non pas une référence.Par conséquent, vous ne pouvez pas écrire dans un objet texture à l'aide de texture::operator[], opérateur.

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

L'exemple de code suivant montre comment inscrire des canaux de texture dans un vecteur court, puis comment accèder aux éléments scalaires individuels en tant que propriétés du vecteur court.

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

Le tableau suivant répertorie les bits valides par canal pour chaque type de vecteur de tri.

Type de données de texture

Bits valides par élément scalaire

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(fr-fr,VS.110).gifÉcrire dans des objets Texture

Utilisez la méthode texture::set pour écrire dans des objets texture.Un objet de texture peut être en lecture seule ou en lecture/écriture.Pour qu'un objet de texture soit lisible et accessible en écriture, les conditions suivantes doivent être remplies:

  • T possède seulement un composant scalaire.(Les vecteurs courts ne sont pas autorisés.)

  • T n'est pas double, norm, ou unorm.

  • La propriété texture::bits_per_scalar_element est 32.

Si toutes trois ne sont pas vraies, l'objet texture est en lecture seule.Les deux premières conditions sont vérifiées pendant la compilation.Une erreur de compilation est générée si votre code essaie d'écrire dans un objet de texture readonly.La condition pour texture::bits_per_scalar_element est détectée au moment de l'exécution, et le runtime génère l'exception unsupported_feature si vous tentez d'écrire dans un objet texture en lecture seule.

L'exemple de code suivant écrit des valeurs dans un objet de texture.

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(fr-fr,VS.110).gifUtiliser un objet _texture_view accessible en écriture uniquement

La classe writeonly_texture_view fournit une vue writeonly d'un objet de texture.L'objet writeonly_texture_view doit être capturé par valeur dans l'expression lambda.L'exemple de code suivant utilise un objet writeonly_texture_view pour écrire dans un objet texture à deux composants (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(fr-fr,VS.110).gifCopie d'objets Texture

Vous pouvez effectuer des copies entre objets de texture à l'aide de la fonction copy ou de la fonction copy_async, comme indiqué dans l'exemple de code suivant.

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

Vous pouvez également effectuer des copies d'une texture à une autre à l'aide de la méthode texture::copy_to.Les deux textures peuvent être sur des accelerator_views différents.Lorsque vous effectuez une copie vers un objet writeonly_texture_view, les données sont copiées à l'objet texture sous-jacent.Les bits par élément scalaire et l'extent doivent être identiques sur les objets texture de source et de destination.Si ces conditions ne sont pas satisfaites, le runtime lève une exception.

Interopérabilité

Le C++ AMP prend en charge l'interopérabilité entre texture<T,1> et l' interface d'ID3D11Texture1D, entre texture<T,2> et l' interface d'ID3D11Texture2D, et entre texture<T,3> et l' interface d'ID3D11Texture3D.La méthode get_texture prend un objet de type texture et retourne une interface de type IUnknown.La méthode make_texture prend une interface de type IUnknown et un objet de type accelerator_view. Elle retourne un objet de type texture.

Voir aussi

Référence

double_2, classe

double_3, classe

double_4, classe

float_2, classe

float_3, classe

float_4, classe

int_2, classe

int_3, classe

int_4, classe

norm_2, classe

norm_3, classe

norm_4, classe

short_vector Structure

short_vector_traits Structure

uint_2, classe

uint_3, classe

uint_4, classe

unorm_2, classe

unorm_3, classe

unorm_4, classe