Gráficos (C++ AMP)
O AMP C++ contém vários APIs no namespace Concurrency::graphics que você pode usar para acessar o suporte de textura em GPUs.Alguns cenários comuns são:
Você pode usar a classe textura como um recipiente de dados para a computação e explorar a localidade espacial de cache de textura e os layouts de hardware de GPU.A localidade é espacial a propriedade dos elementos de dados que são fisicamente perto uns dos outros.
O runtime fornece a interoperabilidade eficiente com shaders não-computados.O pixel, o vértice, o tesselation e os shaders de casca freqüentemente consomem ou geram texturas que você pode usar em suas cálculos de AMP C++.
APIs de elementos gráficos do AMP C++ fornecem maneiras alternativas para acessar buffers empacotados em sub-palavras.As texturas que possuem os formatos que representam os texels (elementos de textura) que são compostos de escalares de 8 bits ou 16 bits permitem o acesso a um armazenamento de dados empacotado.
Observação |
---|
APIs de AMP C++ não fornecem funcionalidade de amostragem e filtragem de textura.Você deve usar os recursos de interoperabilidade de AMP C++ e escrever código em DirectCompute e em HLSL. |
Os tipos de norma e de unorm
Os tipos norm e unorm são os tipos escalares que limitam o intervalo de valores float ; isso é conhecido como compressão.Esses tipos podem ser explicitamente construídos de outros tipos escalares.Em a conversão, o valor é inicialmente convertido para float e comprimido na região respectiva que é permitida por norm [-1.0…1.0] ou unorm [0.0…1.0].Converão de +/- infinito retorna +/-1.Conversão de NaN é indefinida.Uma norma pode ser implicitamente construído de um unorm e não há nenhuma perda de dados.O operador de conversão implícita para flutuante é definido nesses tipos.Os operadores binários são definidos entre esses tipos e outros tipos internos escalares como float e int: +, -, *,/, ==! =, >, <, >=, <=.Operadores de atribuição composta também são suportados: +=, - =, *=, /=.O operador unário de negação (-) é definido para tipos norm.
Biblioteca de vetor curto
A biblioteca de vetor curto fornece algumas das funcionalidades do Tipo vetorial que é definido em HLSL e é normalmente usado para definir texels.Um vetor curto é uma estrutura de dados que contém um a quatro valores do mesmo tipo.Os tipos suportados são double, float, int, norm, uint, e unorm.Nomes dos tipo são mostrados na tabela a seguir.Para cada tipo, há também um typedef correspondente que não tem um sublinhado no nome.Os tipos que têm sublinhados estão em Namespace Concurrency::Graphics.Tipos que não têm sublinhados estão em Namespace Concurrency::Graphics::Direct3D de modo que sejam claramente separados dos tipos similarmente nomeados fundamentais como __int8 e __int16.
Comprimento 2 |
Comprimento 3 |
Comprimento 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 |
Operadores
Se um operador é definido entre dois vetores curtos, então é definido também entre um vetor curto e um escalar.Além de isso, um desses deve ser verdadeiro:
O tipo de escalar deve ser o mesmo que o tipo de elemento curto do vetor.
O tipo de escalar pode ser convertida implicitamente para o tipo de elemento vetorial usando apenas uma conversão definido pelo usuário.
A operação é o componente inteiro especificado entre cada componente do vetor curto e o escalar.Aqui estão os operadores válidos:
Tipo de operador |
Tipos válidos |
---|---|
Operadores binários |
Válido em todos os tipos: +, -, *,/, Válido em tipos inteiros: %, ^, |, &, <<, >> Os dois vetores devem ter o mesmo tamanho, e o resultado é um vetor do mesmo tamanho. |
Operadores relacionais |
Válido em todos os tipos: == e != |
Operador de atribuição composta |
Válido em todos os tipos: +=, -=, *= ,/=, Válido em tipos inteiros: %=, ^=, |=, &=, <<=, >>= |
Operadores de incremento e de decremento |
Válido em todos os tipos: ++, -- Ambos o prefixo e o sufixo são válidos. |
Operador NOT bit a bit (~) |
Válido em tipos inteiros. |
Operador unário |
Válido em todos os tipos exceto unorm e uint. |
Expressões de Swizzling
A biblioteca de vetor pequeno oferece suporte ao acessador de construção vector_type.identifier para acessar os componentes de um vetor curto.O identifier, que é conhecido como uma expressão swizzling, especifica os componentes do vetor.A expressão pode ser um valor l ou um valor r.Os caracteres individuais no identificador podem ser: x, y, z, e w; ou r, g, b, e A. “x” e “r” representam zero-ésimo componente, “y” e “g” representam o primeiro componente, e assim por diante.(Observe que “x” e “r” não podem ser usados no mesmo identificador.) Portanto, “rgba” e “xyzw" retornam o mesmo resultado.Assessores de um componente como “x” e “y” são tipos de valor escalar.Assessores de vários componentes são tipos de vetor curtos.Por exemplo, se você constrói um vetor int_4 que é chamado fourInts e têm valores 2, 4, 6, e 8, então fourInts.y retorna o número inteiro 4 e fourInts.rg retorna um objeto int_2 que possui os valores 2 e 4.
Classes de textura
Muito GPUs têm hardware e os caches que são otimizados para buscar pixels e texels e processar imagens e texturas.A classe textura<T,N> , que é uma classe recipiente para objetos de texel, expõe a funcionalidade de textura desses GPUs.Um texel pode ser:
Um int, uint, float, double, norm, ou unorm escalar.
Um vetor curto que possui dois ou quatro componentes.A única exceção é double_4, que não é permitida.
O objeto texture pode ter uma classificação de 1, 2, ou 3.O objeto texture pode ser detectado somente por referência no método de uma chamada a parallel_for_each.A textura é armazenada em GPU como objetos de textura de Direct3D.Para obter mais informações sobre as texturas e de texels em Direct3d, consulte Introdução às texturas em Direct3D 11.
O tipo de texel você usa pode ser um dos muitos formatos de textura que são usadas na programação de elementos gráficos.Por exemplo, um formato de RGBA pode usar 32 bits, com 8 bits para cada um dos elementos escalares R, G, B e A.O hardware textura de uma placa gráfica pode acessar elementos baseados em formato.Por exemplo, se você estiver usando o formato de RGBA, o hardware de textura pode extrair cada elemento de 8 bits em um formulário de 32 bits.Em AMP C++, você pode definir os bits por elemento escalar do seu texel para que você possa automaticamente acessar elementos individuais escalares no código sem usar o deslocamento de bits.
Criando uma instância de textura objetos
Você pode declarar um objeto de textura sem inicialização.O exemplo de código declara vários 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));
}
Você também pode usar um construtor para declarar e inicializar um objeto texture.O exemplo de código a seguir cria uma instância de um objeto texture de um vetor de objetos float_4 .Os bits por elemento escalar são definidos como padrão.Você não pode usar esse construtor com norm, unorm, ou vetores curtas de norm e de unorm, porque eles não têm um padrão de bits por 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());
}
Você pode também declarar e inicializar um objeto texture usando uma sobrecarga do construtor que utiliza um ponteiro para os dados de origem, o tamanho dos dados de origem em bytes, e a bit 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);
}
As texturas nesses exemplos são criadas no modo de exibição padrão de aceleradores padrão.Você pode usar outras sobrecargas de construtor se você desejar especificar um objeto accelerator_view.Você não pode criar um objeto de textura em um acelerador CPU.
Há um limite no tamanho de cada dimensão de objeto texture, conforme mostrado na tabela.Um erro em tempo de execução é gerado se você exceder os limites.
Textura |
Limite de tamanho |
---|---|
textura<T,1> |
16384 |
textura<T,2> |
16384 |
textura<T,2> |
2048 |
Ler de objetos de textura
Você pode ler a partir de um objeto texture usando textura::operador[] o operador, textura:: () dooperadoroperador ou Método de Texture::Get.textura::operador[] o operador e textura:: () dooperadoroperador retornam um valor, não uma referência.Portanto, você não pode gravar em um objeto texture usando textura::operador[] o 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();
}
O exemplo de código a seguir demonstra como armazenar os canais de textura em um vetor curto e em seguida, acessa os elementos individuais escalares como propriedades do vetor curto.
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;
});
}
A tabela a seguir lista os bits por canal válidos para cada tipo do vetor tipo.
Tipo de dados de textura |
Bit válidos pelo 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 |
Gravando em objetos de textura
Use o método texture::set para gravar os objetos de texture.Um objeto de textura podem ser aleatórios ou de leitura/gravação.Para que um objeto de textura seja legível e gravável, as seguintes condições devem ser verdadeiras:
T tem apenas um componente escalar.(Vetores curtos não são permitidos.)
T não é double, norm, ou unorm.
A propriedade texture::bits_per_scalar_element é 32.
Se todos os três não são verdade, então o objeto texture é aleatório.As duas primeiras condições são verificadas durante a compilação.Um erro de compilação é gerado se você tiver o código que tenta escrever em um objeto de textura readonly.A condição de texture::bits_per_scalar_element é detectada em tempo de execução, e o tempo de execução gera a exceção unsupported_feature se você tentar gravar em um objeto aleatório de texture .
Os códigos a seguir gravam os valores em um objeto de textura.
void writeTexture() {
texture<int, 1> tex1(16);
parallel_for_each(tex1.extent, [&tex1] (index<1> idx) restrict(amp) {
tex1.set(idx, 0);
});
}
Usando um objeto de writeonly_texture_view
A classe writeonly_texture_view fornece uma exibição writeonly (somente escrita) de um objeto de textura.O objeto writeonly_texture_view deve ser detectado pelo valor na expressão lambda.O exemplo de código usa um objeto writeonly_texture_view para gravar um objeto texture que possui dois 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));
});
}
Copiando objetos de textura
O uso pode fazer copias entre objetos de textura usando as funções impressão ou copy_async, conforme mostrado no exemplo de código a seguir.
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));
}
Você também pode copiar de uma textura a outra usando o método texture::copy_to .As duas texturas podem estar em accelerator_views diferentes.Quando você copia um objeto writeonly_texture_view, os dados são copiados para o objeto subjacente texture.Os bits por elemento escalar e a extensão devem ser os mesmos em objetos de orgiem e destino texture.Se os requisitos não são atendidos, o tempo de execução gera uma exceção.
Interoperabilidade
O tempo de execução de AMP C++ oferece suporte à interoperabilidade entre texture<T,1> e interface de ID3D11Texture1D, entre texture<T,2> e interface de ID3D11Texture2D, e entre texture<T,3> e interface de ID3D11Texture3D.O método get_texture utiliza um objeto texture e retorna uma interface IUnknown .O método make_texture usa uma interface IUnknown e um objeto accelerator_view e retorna um objeto texture.