Grafica (C++ AMP)

C++ AMP contiene diverse API nello spazio dei nomi Concurrency::graphics che è possibile utilizzare per accedere al supporto texture su GPU.Alcuni scenari comuni sono:

  • È possibile utilizzare la classe texture come contenitore di dati per calcoli e sfruttare la località spaziale della cache della texture e dei layout dell'hardware di GPU.La località spaziale è la proprietà di elementi di dati che sono fisicamente vicini tra loro.

  • Il runtime fornisce interoperabilità più efficiente con shader non di elaborazione.Pixel, vertex, tesselation e hull shader spesso utilizzano o producono texture utilizzabili nei calcoli di C++ AMP.

  • Le API grafiche di C++ AMP offrono modalità alternative di accesso ai buffer sub-word compressi.Le texture con formati che rappresentano texels (elementi di texture) costituiti da scalari a 8 bit o 16 bit consentono l'accesso alla memorizzazione dei dati compatta.

[!NOTA]

Le API di C++ AMP non forniscono il campionamento di texture e la funzionalità di filtro.È necessario utilizzare le funzionalità di interoperabilità di C++ AMP e scrivere codice in DirectCompute e in HLSL.

I tipi norm e unorm

I tipi norm e unorm sono tipi scalari che limitano l'intervallo dei valori di float ; questo è noto come clamping.Questi tipi possono essere creati in modo esplicito da altri tipi scalari.Durante l'azione di cast, viene prima eseguito il cast sul valore a float e poi eseguito il clamp alla relativa area consentita da norm [- 1,0… 1,0] o da unorm [0,0… 1,0].Il cast da +/- infinito restituisce +/- 1.Il cast da NaN è indefinito.Un norm può essere costruito in modo implicito da un unorm e non comporta alcuna perdita di dati.L'operatore di conversione implicita verso float è definito su questi tipi.Gli operatori binari sono definiti tra questi tipi e altri tipi scalari predefiniti, ad esempio float e int: +, -, *, /, ==, !=, >, <, >=, <=.Anche gli operatori di assegnamento composti sono supportati: +=, - =, *=,/=.Per i tipi norm è definito l'operatore di negazione unario (-).

Libreria Short Vector

La libreria Short Vector fornisce alcune funzionalità del Tipo Vettore definito in HLSL e in genere utilizzato per definire i texels.Un short vector è una struttura dati che contiene da uno a quattro valori dello stesso tipo.I tipi supportati sono double, float, int, norm, uint, e unorm.I nomi dei tipi sono riportati nella tabella seguente.Per ciascun tipo, c'è anche un typedef corrispondente che non ha un carattere di sottolineatura nel nome.I tipi con caratteri di sottolineatura sono nello spazio dei nomi Spazio dei nomi Concurrency::graphics.I tipi che non dispongono di carattere di sottolineatura sono nello spazio dei nomi Spazio dei nomi Concurrency::graphics::direct3d in modo da essere separati chiaramente dai tipi fondamentali denominati allo stesso modo, ad esempio __int8 e __int16.

Lunghezza 2

Lunghezza 3

Lunghezza 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(it-it,VS.110).gifOperatori

Se un operatore è definito tra due short vector, viene definito anche tra un short vector e uno scalare.Inoltre, una di queste deve essere vera:

  • Il tipo dello scalare deve essere uguale al tipo di elemento del short vector.

  • Il tipo dello scalare può essere convertito in modo implicito nel tipo di elemento del vettore tramite una sola conversione definita dall'utente.

L'operazione è come un componente incluso tra ogni componente di short vector e l'operatore scalare.Di seguito sono mostrati gli operatori validi:

Tipo di operatore

Tipi validi

Operatori binari

Validi per tutti i tipi: +, -, *, /,

Validi su tipi integer: %, ^, |, &, <<, >>

I due vettori devono avere la stessa dimensione e il risultato è un vettore della stessa dimensione.

Operatori relazionali

Validi per tutti i tipi: == e !=

Operatore di assegnazione composta

Validi per tutti i tipi: +=, -=, *=, /=

Validi su tipi integer: %=, ^=, |=, &=, <<=, >>=

Operatori di incremento e decremento

Validi per tutti i tipi: ++, --

Prefisso e suffisso sono validi.

Operatore NOT bit a bit (~)

Validi su tipi integer.

Operatore unario -

Valido per tutti i tipi eccetto unorm e uint.

Hh913015.collapse_all(it-it,VS.110).gifEspressioni swizzling

La Libreria Short Vector supporta il costrutto di accesso vector_type.identifier per accedere ai componenti di un short vector.L' identifier, conosciuto come espressione swizzling, specifica i componenti del vettore.L'espressione può essere un l-value o un r-value.I singoli caratteri nell'identificatore possono essere: x, y, z, e w; oppure r, g, b e a.x" e "r" rappresentano il componente zero-esimo, "y" e "g" rappresentano il primo componente, e così via.(Si noti che "x" e "r" non possono essere utilizzate nello stesso identificatore). Di conseguenza, "rgba" e "xyzw" restituiscono lo stesso risultato.Le funzioni di accesso di una singola componente come "x" e "y" sono tipi di valore scalari.Le funzioni di accesso a più componenti sono tipi short vector.Ad esempio, se si crea un vettore di int_4 denominato fourInts con i valori 2, 4, 6 e 8, allora fourInts.y restituisce l'intero 4 e fourInts.rg restituisce un oggetto int_2 con i valori 2 e 4.

Classi di texture

Molte GPU hanno hardware e cache ottimizzate per recuperare pixel e texel ed eseguire il rendering delle immagini e delle texture.La classe texture<T,N>, una classe di contenitori per gli oggetti di texel, espone la funzionalità di texture di queste GPUs.Un texel può essere:

  • Uno scalare int, uint, float, double, norm, o unorm.

  • Un short vector con due o quattro componenti.L'unica eccezione è double_4, che non è consentita.

L'oggetto texture può avere rango 1, 2, o 3.L'oggetto texture può essere acquisito solo per riferimento nella lambda di una chiamata a parallel_for_each.La texture viene memorizzata su GPU come oggetti di texture Direct3D.Per ulteriori informazioni su trame e i texel in Direct3D, vedere Introduzione alle Trame in Direct3D 11.

Il tipo texel utilizzato può essere uno dei numerosi formati di texture utilizzati nella programmazione di grafica.Ad esempio, un formato RGBA potrebbe utilizzare 32 bit, con 8 bit per ogni elemento scalare R, G, B e A.L'hardware di texture di una scheda grafica può accedere ai singoli elementi in base al formato.Ad esempio, se si utilizza il formato RGBA, l'hardware di texture consente di estrarre ciascun elemento a 8 bit in una forma a 32 bit.In C++ AMP, è possibile impostare i bit per elemento scalare del texel per consentire l'accesso automatico ai singoli elementi scalari nel codice senza scorrere i bit.

Hh913015.collapse_all(it-it,VS.110).gifIstanziazione di Oggetti Texture

È possibile dichiarare un oggetto texture senza inizializzazione.Nell'esempio di codice seguente vengono dichiarati diversi oggetti 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));
}

È inoltre possibile utilizzare un costruttore per dichiarare e inizializzare un oggetto texture.Nell'esempio di codice seguente viene creata un'istanza di un oggetto texture da un vettore di oggetti float_4.I bit per elemento scalare sono impostati sul valore predefinito.Non è possibile utilizzare questo costruttore con norm, unorm, o short vector di norm e unorm, poiché non hanno bit predefiniti per elemento scalare.

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

È anche possibile dichiarare e inizializzare un oggetto texture utilizzando un overload del costruttore che accetta un puntatore ai dati di origine, la dimensione dei dati di origine in byte e i bit per elemento scalare.

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

Le trame in questi esempi vengono creati nella visualizzazione predefinita dell'acceleratore predefinito.È possibile utilizzare altri overload del costruttore se si desidera specificare un oggetto accelerator_view.Non è possibile creare un oggetto texture su un acceleratore della CPU.

Esistono limiti alla grandezza di ogni dimensione dell'oggetto texture, come illustrato nella tabella seguente.Viene generato un errore a runtime se si superano i limiti.

Trama

Limitazione delle dimensioni

texture<T,1>

16384

texture<T,2>

16384

texture<T,2>

2048

Hh913015.collapse_all(it-it,VS.110).gifLettura da Oggetti Trama

È possibile leggere da un oggetto texture utilizzando gli operatori Operatore texture::operator[], Operatore texture::operator(), o il metodo Metodo texture::get.Gli operatori Operatore texture::operator[] e Operatore texture::operator() restituiscono un valore, non un riferimento.Di conseguenza, non è possibile scrivere un oggetto texture utilizzando l'operatore Operatore texture::operator[].

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

Nell'esempio di codice seguente viene illustrato come archiviare i canali di texture in un short vector e accedere quindi ai singoli elementi scalari come proprietà del short vector.

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

Nella tabella seguente sono elencati i bit per canale validi per ogni tipo di ordinamento del vettore.

Tipo di dati Trama

Bit validi per elemento scalare

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(it-it,VS.110).gifScrittura su Oggetti Trama

Utilizzare il metodo texture::set per scrivere in oggetti texture.Un oggetto texture può essere di sola lettura o lettura /scrittura.Affinché un oggetto texture sia leggibile e modificabile, le condizioni seguenti devono essere vere:

  • T ha solo un componente scalare.(Short vectors non sono consentiti.)

  • T non è double, norm, o unorm.

  • La proprietà texture::bits_per_scalar_element è 32.

Se tutte e tre non sono vere, l'oggetto texture è di sola lettura.Le prime due condizioni sono verificate durante la compilazione.Un errore di compilazione viene generato se si utilizza codice che prova a scrivere in un oggetto texture readonly.La condizione per texture::bits_per_scalar_element viene rilevata in fase di esecuzione, e il runtime genera l'eccezione unsupported_feature se si tenta di scrivere in un oggetto texture di sola lettura.

Nell'esempio di codice seguente vengono scritti dei valori in un oggetto 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(it-it,VS.110).gifUtilizzo di un Oggetto writeonly_texture_view

La classe writeonly_texture_view fornisce una visualizzazione in sola scrittura di un oggetto texture.L'oggetto writeonly_texture_view deve essere acquisito per valore nella lambda espressione.Nell'esempio di codice seguente viene utilizzato un oggetto writeonly_texture_view per scrivere un oggetto texture con due componenti (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(it-it,VS.110).gifCopia di Oggetti Trama

E' possibile eseguire copie tra oggetti texture utilizzando la funzione copy o la funzione copy_async, come illustrato nell'esempio di codice.

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

È anche possibile copiare da una texture a un'altra utilizzando il metodo texture::copy_to.Le due trame possono essere in accelerator_views diversi.Quando si copia in un oggetto writeonly_texture_view, i dati vengono copiati nell'oggetto texture sottostante.I bit per elemento scalare e l'extent devono essere uguali negli oggetti texture di destinazione e di origine.Se tali richieste non vengono soddisfatte, il runtime genera un'eccezione.

Interoperabilità

Il runtime C++ AMP supporta l'interoperabilità tra texture<T,1> e l' interfaccia ID3D11Texture1D, tra texture<T,2> e l' interfaccia di ID3D11Texture2D e tra texture<T,3> e l' interfaccia ID3D11Texture3D.Il metodo get_texture accetta un oggetto texture e restituisce un'interfaccia IUnknown.Il metodo make_texture accetta un'interfaccia IUnknown e un oggetto accelerator_view e restituisce un oggetto texture.

Vedere anche

Riferimenti

Classe 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

Struttura short_vector

Struttura short_vector_traits

Classe uint_2

Classe uint_3

Classe uint_4

Classe unorm_2

Classe unorm_3

Classe unorm_4