Compartilhar via


Conversão de tipo de dados

As seções a seguir descrevem como o Direct3D lida com conversões entre tipos de dados.

Terminologia de tipo de dados

O conjunto de termos a seguir é usado posteriormente para caracterizar várias conversões de formato.

Termo Definição
SNORM Inteiro normalizado com sinal, o que significa que, para um número de complemento de n-bit 2, o valor máximo significa 1,0f (por exemplo, o valor 01111 de 5 bits mapeia para 1,0f) e o valor mínimo significa -1,0f (por exemplo, o valor 10000 de 5 bits mapeia para -1,0f). Além disso, o segundo número mínimo mapeia para -1,0f (por exemplo, o valor10001 de 5 bits mapeia para -1,0f). Há, portanto, duas representações de inteiros para -1,0f. Há uma única representação para 0,0f e uma única representação para 1,0f. Isso resulta em um conjunto de representações de inteiros para valores de ponto flutuante espaçados uniformemente no intervalo (-1,0f...0,0f) e também um conjunto complementar de representações para números no intervalo (0,0f... 1,0f)
UNORM Inteiro normalizado sem sinal, o que significa que, para um número de n-bits, todos os 0 significam 0,0f e todos os 1 significam 1,0f. Uma sequência de valores de ponto flutuante espaçados uniformemente de 0,0f a 1,0f são representados. por exemplo, um UNORM de 2 bits representa 0,0f, 1/3, 2/3 e 1,0f.
SINT Inteiro com sinal. Inteiro do complemento de 2. por exemplo, um UINT de 3 bits representa os valores integrais 0, 1, 2, 3, 4, 5, 6, 7.
UINT Inteiro sem sinal. por exemplo, um UINT de 3 bits representa os valores integrais 0, 1, 2, 3, 4, 5, 6, 7.
FLOAT Um valor de ponto flutuante em uma das representações definidas pelo Direct3D.
SRGB Semelhante a UNORM pois, para um número de n-bits, todos os 0 significam 0,0f e todos os 1 significam 1,0f. No entanto, ao contrário do UNORM, com SRGB a sequência de codificações de inteiros sem sinal entre todos os 0 para todos os 1 representa uma progressão não linear na interpretação de ponto flutuante dos números, entre 0,0f a 1,0f. De um modo geral, se essa progressão não linear, SRGB, fosse exibida como uma sequência de cores, ela apareceria como uma rampa linear de níveis de luminosidade para um observador “médio”, em condições de visualização “médias”, em uma exibição "média". Para obter detalhes completos, veja o padrão de cores SRGB, IEC 61996-2-1, na IEC (International Electrotechnical Commission).

 

Os termos acima são frequentemente usados como “Modificadores de nome de formato”, em que eles descrevem como os dados são dispostos na memória e que conversão será executada no caminho de transporte (possivelmente incluindo filtragem) da memória de ou para uma unidade de pipeline, como um sombreador.

Conversão de ponto flutuante

Sempre que ocorre uma conversão de ponto flutuante entre representações diferentes, incluindo de representações de ponto não flutuante ou para representações de ponto não flutuante, aplicam-se as regras a seguir.

Convertendo de uma representação de intervalo superior para uma representação de intervalo inferior

  • Arredondamento para zero é usado durante a conversão para outro formato flutuante. Se o destino é um número inteiro ou formato de ponto fixo, é usado o arredondamento para o número par mais próximo, a menos que a conversão seja explicitamente documentada com o uso de outro comportamento de arredondamento, como arredondamento para o mais próximo em FLOAT para SNORM, FLOAT para UNORM ou FLOAT para SRGB. Outras exceções são as instruções de sombreador ftoi e ftou, que usam o arredondamento para zero. Por fim, as conversões de flutuante para fixo usadas pela amostra de textura e pelo rasterizador têm uma tolerância especificada medida em ULP (Unit-Last-Place) de um ideal infinitamente preciso.
  • Para valores de origem maiores do que o intervalo dinâmico de um formato de destino de intervalo inferior (por exemplo, um valor flutuante grande de 32 bits é gravado em um float RenderTarget de 16 bits), resulta o valor máximo representável (com sinal apropriado), NÃO incluindo o infinito com sinal (devido ao arredondamento para zero descrito acima).
  • NaN (não é um número) em um formato de intervalo superior será convertido em representação NaN no formato de intervalo inferior se a representação NaN existir no formato de intervalo inferior. Se o formato inferior não tiver uma representação NaN, o resultado será 0.
  • INF em um formato de intervalo inferior será convertido na representação INF no formato de intervalo superior se disponível no formato de intervalo superior. Se o formato inferior não tiver uma representação INF, ele será convertido para o valor máximo representável. O sinal será preservado, se disponível no formato de destino.
  • A Denorm (desnormalização) em um formato de intervalo superior será convertida para a representação Denorm no formato de intervalo inferior, se disponível no formato de intervalo inferior e a conversão for possível. Caso contrário, o resultado será 0. O bit de sinal será preservado, se disponível no formato de destino.

Conversão de uma representação de intervalo inferior para uma representação de intervalo superior

  • NaN em um formato de intervalo inferior será convertido na representação NaN no formato de intervalo superior se a representação NaN existir no formato de intervalo superior. Se o formato de intervalo superior não tiver uma representação NaN, ele será convertido em 0.
  • INF em um formato de intervalo inferior será convertido na representação INF no formato de intervalo superior se disponível no formato de intervalo superior. Se o formato superior não tiver uma representação INF, ele será convertido para o valor máximo representável (MAX_FLOAT nesse formato). O sinal será preservado, se disponível no formato de destino.
  • A Denorm em um formato de intervalo inferior será convertida em uma representação normalizada no formato de intervalo superior, se possível, ou então em uma representação Denorm no formato de intervalo superior, se a representação Denorm existir. Caso contrário, se o formato de intervalo superior não tiver uma representação Denorm, ele será convertido em 0. O sinal será preservado, se disponível no formato de destino. Observe que os números flutuantes de 32 bits contam como um formato sem uma representação Denorm (porque Denorms em operações em números flutuantes de 32 bits tendem a 0 com sinal preservado).

Conversão de inteiros

A tabela a seguir descreve as conversões de várias representações descritas acima para outras representações. Somente as conversões que realmente ocorrem no Direct3D são mostradas.

Com números inteiros, a menos que especificado de outra forma, todas as conversões de/para representações de números inteiros para as representações de número flutuante descritas abaixo serão feitas com exatidão.

Tipo de dados de origem Tipo de dados de destino Regra de conversão
SNORM FLOAT

Dado um valor inteiro de n bits que representa o intervalo com sinal [-1,0f a 1,0f], a conversão para ponto flutuante é como mostrado a seguir.

  • O valor mais negativo é mapeado para -1,0f. por exemplo, o valor 10000 de 5 bits mapeia para -1,0f.
  • Todos os outros valores são convertidos em um número flutuante (vamos chamá-lo de c), e o resultado = c * (1,0f/(2⁽ⁿ⁻¹⁾-1)). Por exemplo, o valor 10001 de 5 bits é convertido em -15,0f e, em seguida, dividido por 15,0f, gerando -1,0f.
FLOAT SNORM

Dado um número de ponto flutuante, a conversão para um valor inteiro de n bits que representa o intervalo com sinal [-1,0f a 1,0f] é como mostrado a seguir.

  • Deixe c representar o valor inicial.
  • Se c é NaN, o resultado é 0.
  • Se c > 1,0f, incluindo INF, ele é fixado em 1,0f.
  • Se c < -1,0f, incluindo -INF, ele é fixado em -1,0f.
  • Converter de escala flutuante para escala de inteiros: c = c * (2ⁿ⁻¹-1).
  • Converta em um inteiro como mostrado a seguir.
    • Se c >= 0, então c = c + 0,5f, caso contrário, c = c - 0,5f.
    • Descarte a fração decimal e o valor de ponto flutuante (inteiro) restante é convertido diretamente em um inteiro.

Essa conversão permite uma tolerância de D3Dxx_FLOAT32_TO_INTEGER_TOLERANCE_IN_Unit-Last-Place Unit-Last-Place (no lado inteiro). Isso significa que, após a conversão de ponto flutuante para a escala de inteiros, qualquer valor dentro de D3Dxx_FLOAT32_TO_INTEGER_TOLERANCE_IN_ULP Unit-Last-Place de um valor de formato de destino representável tem permissão para mapear para esse valor. O requisito adicional de capacidade de inversão de dados garante que a conversão não seja decrescente em todo o intervalo e que todos os valores de saída sejam atingíveis. (Nas constantes mostradas aqui, xx deve ser substituído pela versão Direct3D, por exemplo, 10, 11 ou 12.)

UNORM FLOAT

O valor inicial de n-bits é convertido em flutuante (0,0f, 1,0f, 2,0f etc.) e dividido por (2ⁿ-1).

FLOAT UNORM

Deixe c representar o valor inicial.

  • Se c é NaN, o resultado é 0.
  • Se c > 1,0f, incluindo INF, ele é fixado em 1,0f.
  • Se c < 0,0f, incluindo -INF, ele é fixado em 0,0f.
  • Converter de escala flutuante para escala de inteiros: c = c * (2ⁿ-1).
  • Converta em inteiro.
    • c = c + 0,5f.
    • A fração decimal é descartada e o valor de ponto flutuante (inteiro) restante é convertido diretamente em um inteiro.

Essa conversão permite uma tolerância de D3Dxx_FLOAT32_TO_INTEGER_TOLERANCE_IN_ULP Unit-Last-Place (no lado inteiro). Isso significa que, após a conversão de ponto flutuante para a escala de inteiros, qualquer valor dentro de D3Dxx_FLOAT32_TO_INTEGER_TOLERANCE_IN_ULP Unit-Last-Place de um valor de formato de destino representável tem permissão para mapear para esse valor. O requisito adicional de capacidade de inversão de dados garante que a conversão não seja decrescente em todo o intervalo e que todos os valores de saída sejam atingíveis.

SRGB FLOAT

A seguir, é mostrada a conversão ideal de SRGB para FLOAT.

  • Pegue o valor inicial de n-bits, converta-o em flutuante (0,0f, 1,0f, 2,0f etc.); chame isso de c.
  • c = c * (1,0f/(2ⁿ-1))
  • Se (c < = D3Dxx_SRGB_TO_FLOAT_THRESHOLD), resulta = c / D3Dxx_SRGB_TO_FLOAT_DENOMINATOR_1, caso contrário, resulta = ((c + D3Dxx_SRGB_TO_FLOAT_OFFSET)/D3Dxx_SRGB_TO_FLOAT_DENOMINATOR_2)D3Dxx_SRGB_TO_FLOAT_EXPONENT

Essa conversão permite uma tolerância de D3Dxx_SRGB_TO_FLOAT_TOLERANCE_IN_ULP Unit-Last-Place (no lado de SRGB).

FLOAT SRGB

A seguir, é mostrada a conversão ideal de FLOAT -> SRGB.

Pressupondo que o componente de cor SRGB de destino tenha n bits:

  • Suponha que o valor inicial seja c.
  • Se c é NaN, o resultado é 0.
  • Se c > 1,0f, incluindo INF, ele é fixado em 1,0f.
  • Se c < 0,0f, incluindo -INF, ele é fixado em 0,0f.
  • Se (c <= D3Dxx_FLOAT_TO_SRGB_THRESHOLD), c = D3Dxx_FLOAT_TO_SRGB_SCALE_1 * c, caso contrário: c = D3Dxx_FLOAT_TO_SRGB_SCALE_2 * c(D3Dxx_FLOAT_TO_SRGB_EXPONENT_NUMERATOR/D3Dxx_FLOAT_TO_SRGB_EXPONENT_DENOMINATOR) - D3Dxx_FLOAT_TO_SRGB_OFFSET
  • Converter de escala flutuante para escala de inteiros: c = c * (2ⁿ-1).
  • Converta em inteiro:
    • c = c + 0,5f.
    • A fração decimal é descartada e o valor de ponto flutuante (inteiro) restante é convertido diretamente em um inteiro.

Essa conversão permite uma tolerância de D3Dxx_FLOAT32_TO_INTEGER_TOLERANCE_IN_ULP Unit-Last-Place (no lado inteiro). Isso significa que, após a conversão de ponto flutuante para a escala de inteiros, qualquer valor dentro de D3Dxx_FLOAT32_TO_INTEGER_TOLERANCE_IN_ULP Unit-Last-Place de um valor de formato de destino representável tem permissão para mapear para esse valor. O requisito adicional de capacidade de inversão de dados garante que a conversão não seja decrescente em todo o intervalo e que todos os valores de saída sejam atingíveis.

SINT SINT com mais bits

Para converter de SINT para um SINT com mais bits, o MSB (bit mais significativo) do número inicial é “sinal-estendido” para os bits adicionais disponíveis no formato de destino.

UINT SINT com mais bits

Para converter de UINT para um SINT com mais bits, o número é copiado para os LSBs (bits menos significativos) do formato de destino e os MSBs adicionais são preenchidos com 0.

SINT UINT com mais bits

Para converter de SINT para UINT com mais bits: se negativo, o valor é fixado em 0. Caso contrário, o número é copiado para os LSBs do formato de destino e os MSBs adicionais são preenchidos com 0.

UINT UINT com mais bits

Para converter de UINT para um UINT com mais bits, o número é copiado para os LSBs do formato de destino e os MSBs adicionais são preenchidos com 0.

SINT ou UINT SINT ou UINT com menos bits ou iguais

Para converter de um SINT ou UINT para SINT ou UINT com menos bits ou iguais (e/ou alteração no sinal), o valor inicial é simplesmente fixado ao intervalo do formato de destino.

 

Conversão de Inteiro de ponto fixo

Inteiros de ponto fixo são simplesmente inteiros de algum tamanho de bits que têm um ponto decimal implícito em um localização fixa.

O tipo de dados “inteiro” onipresente é um caso especial de um inteiro de ponto fixo com a parte decimal no final do número.

As representações de números de ponto fixo são caracterizadas como: i,f, em que i é o número de bits inteiros e f é o número de bits fracionários. Por exemplo, 16,8 significa 16 bits inteiros seguidos por 8 bits de fração. A parte inteira é armazenada no complemento de 2, pelo menos como definido aqui (embora isso possa ser definido igualmente para inteiros sem sinal, também). A parte fracionária é armazenada em forma sem sinal. A parte fracionária representa sempre a fração positiva entre os dois valores integrais mais próximos, começando do mais negativo.

Operações de adição e subtração com números de ponto fixo são realizadas simplesmente usando aritmética de inteiros padrão, sem considerar onde o decimal implícito se encontra. Adicionar 1 a um número de ponto fixo 16,8 significa apenas adicionar 256, já que o decimal está a 8 casas decimais da extremidade menos significativa do número. Outras operações, como a multiplicação, também podem ser realizadas simplesmente usando a aritmética de inteiros, desde que o efeito sobre o decimal fixo seja considerado. Por exemplo, multiplicar dois inteiros 16,8 usando uma multiplicação de inteiros produz um resultado de 32,16.

As representações de inteiros com ponto fixo são usadas de duas maneiras no Direct3D.

  • As posições de vértice pós-recortadas no rasterizador são fixadas ao ponto fixo, para distribuir uniformemente a precisão pela área RenderTarget. Muitas operações de rasterizador, incluindo face culling como exemplo, ocorrem em posições fixadas de ponto fixo, enquanto outras operações, como a configuração do interpolador de atributos, usam posições que foram convertidas para ponto flutuante das posições fixadas de ponto fixo.
  • As coordenadas de textura para operações de amostragem são fixadas ao ponto fixo (depois de serem dimensionadas por tamanho de textura), para distribuir uniformemente a precisão em todo o espaço de textura, na escolha de localizações/pesos de toque no filtro. Os valores de peso são convertidos em ponto flutuante antes que a aritmética de filtragem real seja executada.
Tipo de dados de origem Tipo de dados de destino Regra de conversão
FLOAT Inteiro de ponto fixo

A seguir é mostrado o procedimento geral para converter um número de ponto flutuante n em um inteiro de ponto fixo i.f, onde i é o número de bits inteiros (com sinal) e f é o número de bits fracionários.

  • Calcular FixedMin = -2⁽ⁱ⁻¹⁾
  • Calcular FixedMax = 2⁽ⁱ⁻¹⁾ - 2(-f)
  • Se n é um NaN, resulta = 0; se n é +Inf, resulta = FixedMax*2f; se n é -Inf, resulta = FixedMin*2f
  • Se n >= FixedMax, resulta = Fixedmax*2f; se n <= FixedMin, resulta = FixedMin*2f
  • Caso contrário, calcule n*2f e converta em inteiro.

As implementações permitem tolerância D3Dxx_FLOAT32_TO_INTEGER_TOLERANCE_IN_ULP Unit-Last-Place no resultado inteiro, em vez do valor infinitamente preciso n*2f após a última etapa acima.

Inteiro de ponto fixo FLOAT

Suponha que a representação de ponto fixo específica que está sendo convertida em flutuante não contenha mais do que um total de 24 bits de informações, não mais do que 23 bits dos quais estão no componente fracionário. Suponha que um dado número de ponto fixo, fxp, esteja na forma i,f (inteiro: i bits, fração: f bits). A conversão para flutuante é semelhante ao pseudocódigo a seguir.

flutuante resulta = (flutuante)(fxp >> flutuante) + // extrair inteiro

((flutuante)(fxp & (2 f - 1)) / (2f)); // extrair fração

 

Apêndices