Este artigo contém algumas das perguntas frequentes sobre o Direct3D 10 do ponto de vista de um desenvolvedor que está portando um aplicativo existente do Direct3D 9 (D3D9) para o Direct3D 10 (D3D10).
Buffers constantes
Qual é a melhor maneira de atualizar buffers constantes?
UpdateSubresource e Map com Discard devem ter a mesma velocidade. Escolha entre eles dependendo de qual copia a menor quantidade de memória. Se você já tiver seus dados armazenados na memória em um bloco contíguo, use UpdateSubresource. Se você precisar acumular dados de outros locais, use Mapa com Descarte.
Qual é a pior maneira de organizar buffers constantes?
O pior desempenho é realizado colocando todas as constantes para um sombreador específico em um buffer constante. Embora essa geralmente seja a maneira mais fácil de portar de D3D9 para D3D10, isso pode impedir o desempenho. Por exemplo, considere um cenário que usa o seguinte buffer constante:
cbuffer VSGlobalsCB
{
matrix ViewProj;
matrix Bones[100];
matrix World;
float SpecPower;
float4 BDRFCoefficients;
float AppTime;
uint2 RenderTargetSize;
};
O buffer é de 6.560 bytes. Suponha que haja um aplicativo com 1000 objetos a serem renderizados, dos quais 100 são malhas esfoladas e 900 dos quais são malhas estáticas. Além disso, suponha que esse aplicativo esteja usando o mapeamento de sombra com uma fonte de luz. Isso significa que há duas passagens, uma para o mapa de profundidade renderizado da luz e outra para o passe de renderização para frente. Isso resulta em chamadas de desenho de 2000. Embora cada chamada de desenho não precise atualizar todas as partes do buffer constante, todo o buffer constante ainda é atualizado e enviado para o cartão. Isso resulta na atualização de 13 MB de dados por quadro (2.000 chamadas de desenho vezes 6560 KB).
Qual é a melhor maneira de organizar meus buffers constantes?
A melhor maneira é organizar buffers constantes por frequência de atualização. As constantes atualizadas em frequências semelhantes devem estar no mesmo buffer. Por exemplo, considere o cenário apresentado em "Qual é a pior maneira de organizar buffers constantes?", mas com um layout de constante melhor:
cbuffer VSGlobalPerFrameCB
{
float AppTime;
};
cbuffer VSPerSkinnedCB
{
matrix Bones[100];
};
cbuffer VSPerStaticCB
{
matrix World;
};
cbuffer VSPerPassCB
{
matrix ViewProj;
uint2 RenderTargetSize;
};
cbuffer VSPerMaterialCB
{
float SpecPower;
float4 BDRFCoefficients;
};
Os buffers constantes são divididos pela frequência de atualização, mas isso é apenas metade da solução. O aplicativo precisa atualizar os buffers constantes corretamente para aproveitar ao máximo a divisão. Vamos supor a mesma cena que acima: 900 malhas estáticas, 100 malhas esfoladas, um passe claro e um passe para frente. Também vamos supor que alguns buffers constantes por objeto serão armazenados. Isso significa que cada objeto conterá um VSPerSkinnedCB ou um VSPerStaticCB, dependendo se ele é ou não esfolado ou estático. Fazemos isso para evitar dobrar a quantidade de matrizes enviadas pelo pipeline.
Dividimos o quadro em três fases. A primeira fase é o início do quadro e não envolve nenhuma renderização, apenas atualizações constantes.
Iniciar Quadro
- Atualizar VSGlobalPerFrameCB para o tempo do aplicativo (4 bytes)
- Atualização 100 VSPerSkinnedCB para os 100 objetos esfolados (640000 bytes)
- Atualizar o VSPerStaticCB para 900 objetos estáticos (57600 bytes)
Em seguida, é a passagem de mapa de sombra. Observe que o único buffer constante que realmente é atualizado é VSPerPassCB. Todos os outros buffers constantes foram atualizados durante a passagem de quadro inicial. Embora ainda precisemos associar esses buffers constantes, a quantidade de informações passadas para o vídeo cartão é mínima, pois os buffers já foram atualizados.
Passe de Sombra
- Atualizar VSPerPassCB (72 bytes)
- Desenhar 100 malhas esfoladas (100 associações, sem atualizações)
- Desenhar 900 malhas estáticas (100 associações, sem atualizações)
Da mesma forma, o passe de renderização para frente só precisa atualizar dados por material, pois não foi armazenado por malha. Se assumirmos que há 500 materiais em uso na cena:
Passagem para Frente
- Atualizar VSPerPassCB (72 bytes)
- Atualização 500 VSPerMaterialCBs (10000 bytes)
Isso resulta em um total de apenas 707 KB. Embora esse seja um cenário muito inventado, ele ilustra a quantidade de sobrecarga de atualização constante que pode ser reduzida classificando constantes por frequência de atualização.
E se eu não tiver espaço suficiente para armazenar buffers constantes individuais para minhas malhas, material e assim por diante?
Você sempre pode usar um sistema em camadas de buffers constantes. Crie buffers constantes de tamanho variável (16 bytes, 32 bytes, 64 bytes e assim por diante) até o maior tamanho de buffer constante necessário. Quando for hora de associar um buffer constante a um sombreador, selecione o menor buffer constante que pode conter os dados necessários para o sombreador. Embora essa abordagem seja um pouco menos eficiente, é uma boa etapa intermediária.
Estou compartilhando buffers constantes entre sombreadores diferentes. Um sombreador pode usar todas as constantes, mas outro pode usar algumas das constantes. Qual é a melhor maneira de atualizá-los?
Uma abordagem é dividir ainda mais o buffer constante. No entanto, chega um ponto em que muitos buffers constantes são associados. Nesse caso, mova as constantes que provavelmente não serão utilizados por vários sombreadores para o final do buffer constante. Ao obter os dados da variável do sombreador, use o sinalizador D3D10_SVF_USED do D3D10_SHADER_VARIABLE_DESC para determinar se a variável é usada. Ao colocar variáveis não utilizadas no final do buffer constante, você pode associar um buffer menor ao sombreador que não usa essas variáveis, economizando assim o custo de atualização.
Quanto posso melhorar minha taxa de quadros se eu carregar apenas os ossos do meu personagem uma vez por quadro em vez de uma vez por passe/desenho?
Você pode melhorar a taxa de quadros entre 8% e 50%, dependendo da quantidade de dados redundantes. Na pior das hipóteses, o desempenho não será reduzido.
Quantos buffers constantes devo ter associado ao mesmo tempo?
Associe o número mínimo de buffers constantes necessários para colocar todos os dados no sombreador. Em um cenário realista, cinco é o número recomendado de buffers constantes a serem usados. Compartilhar buffers constantes entre sombreadores (associar o mesmo CB ao VS e PS) também pode melhorar o desempenho.
Há um custo para associar buffers constantes sem usá-los?
Sim, se você não for realmente usar o buffer, não chame VSSetConsantBuffer ou PSSetConstantBuffer. Essa sobrecarga de API extra pode se somar ao longo de várias chamadas de desenho.
Estado
Qual é a melhor maneira de gerenciar o estado em D3D10?
A melhor solução é conhecer todo o seu estado antecipadamente e criar os objetos de estado antecipadamente. Isso significa que, no momento da renderização, a associação de estado é a única operação que precisa acontecer. D3D10 também filtra duplicatas.
Meu jogo carregou dinamicamente ou tem conteúdo gerado pelo usuário. Não consigo carregar todos os meus objetos de estado antecipadamente. O que devo fazer?
Há duas soluções aqui. A primeira é apenas criar objetos de estado em tempo real e permitir que d3D10 filtre duplicatas. Isso, no entanto, não é recomendado para cenários com muitas alterações de objeto de estado por quadro. Uma solução melhor é hash dos objetos de estado por conta própria e criar um objeto de estado somente se um que se ajusta aos requisitos não for encontrado na tabela de hash. O raciocínio por trás do uso de uma tabela de hash personalizada é que um aplicativo pode selecionar um hash rápido com base no cenário de uso específico a esse aplicativo. Por exemplo, se um aplicativo alterar apenas o rendertargetwritemask no BlendState e mantiver todos os outros valores iguais, o aplicativo poderá gerar um hash do rendertargetwritemask em vez de toda a estrutura.
O estado AlphaTest desapareceu. Onde ele foi parar?
AlphaTest agora deve ser o desempenho no sombreador. Consulte o exemplo FixedFuncEMU.
O que aconteceu com planos de clipe de usuário?
Os planos de clipe do usuário foram movidos para o sombreador. Há duas maneiras de lidar com isso. A primeira é gerar SV_ClipDistance do sombreador de vértice ou do sombreador de geometria. A outra opção é usar descarte no sombreador de pixel com base em algum valor passado pelo sombreador de vértice ou pelo sombreador de geometria. Experimente ambos para ver qual é mais rápido para seu cenário específico. Usar SV_ClipDistance pode fazer com que o hardware use uma rotina de recorte baseada em geometria que pode fazer com que as chamadas de desenho associadas à geometria sejam executadas mais lentamente. Da mesma forma, o uso de descarte desloca o trabalho para o sombreador de pixel, o que pode fazer com que as chamadas de desenho associadas a pixels sejam executadas mais lentamente.
As limpezas não respeitam nenhuma configuração de estado, como minhas configurações de rect de tesoura no meu estado de rasterizador.
As limpezas foram separadas do estado do pipeline. Para obter o comportamento no estilo D3D9, emule as limpezas desenhando um quad de tela inteira.
Defina meus estados como padrão para tentar diagnosticar um erro de renderização. Agora minha tela só mostra preto, embora eu saiba que estou desenhando objetos na tela.
Ao definir o estado de volta para valores padrão (NULL), verifique se o SampleMask na chamada para OMSetBlendState nunca é zero. Se SampleMask estiver definido como zero, todos os exemplos serão logicamente AND com zero. Nesse cenário, nenhum exemplo passará no teste de mesclagem.
Para onde foi o estado D3DSAMP\SRGBTEXTURE?
SRGB foi removido como parte do estado do sampler e agora está vinculado ao formato de textura. Associar uma textura SRGB resultará na mesma amostragem que você obteria se especificasse D3DSAMP_SRGBTEXTURE no Direct3D 9.
Formatos
Qual formato D3D9 corresponde a qual formato D3D10?
Para obter informações, consulte Considerações do Direct3D 9 para Direct3D 10.
O que aconteceu com A8R8G8B8 formatos de textura?
Eles foram preteridos na D3D10. Você pode re-originar suas texturas como R8G8B8A8, ou pode girar na carga ou pode girar no sombreador.
Como fazer usar texturas palettizadas?
Coloque sua paleta de cores em uma textura ou um buffer constante e associe-a ao pipeline. No sombreador de pixel, faça uma pesquisa indireta usando o índice em sua textura palettizada.
Quais são esses novos formatos SRGB?
SRGB foi removido como parte do estado do sampler e agora está vinculado ao formato de textura. Associar uma textura SRGB resultará na mesma amostragem que você obteria se especificasse D3DSAMP_SRGBTEXTURE no Direct3D 9.
Para onde foram os fãs de triângulo?
Os fãs do triângulo foram preteridos em D3D10. Os fãs do triângulo precisarão ser convertidos no pipeline de conteúdo ou no carregamento.
Vinculação do sombreador
Meus sombreadores do Direct3D 9 compilam bem para o Modelo de Sombreador 4.0, mas quando os associo ao pipeline, recebo erros de vinculação aparecendo na saída de depuração com o runtime de depuração.
A vinculação do sombreador é muito mais rigorosa em D3D10. Os elementos em um estágio subsequente devem ser lidos na ordem em que são gerados do estágio anterior. Por exemplo:
Um sombreador de vértice gera:
float4 Pos : SV_POSITION;
float3 Norm : NORMAL;
float2 Tex : TEXCOORD0;
Um sombreador de pixel lê em:
float3 Norm : NORMAL;
float2 Tex : TEXCOORD0;
Embora a posição não seja necessária no sombreador de pixel, isso causará um erro de vinculação, pois a posição está sendo saída do sombreador de vértice, mas não lida pelo sombreador de pixel. A versão mais correta teria esta aparência:
Um sombreador de vértice gera:
float3 Norm : NORMAL;
float2 Tex : TEXCOORD0;
float4 Pos : SV_POSITION;
Um sombreador de pixel lê em:
float3 Norm : NORMAL;
float2 Tex : TEXCOORD0;
Nesse caso, o sombreador de vértice está gerando as mesmas informações, mas agora o sombreador de pixel está lendo itens na saída da ordem. Como o sombreador de pixel não está lendo nada após o Tex, não precisamos nos preocupar que o VS esteja gerando mais informações do que o PS está lendo.
Preciso de uma assinatura de sombreador para criar um Layout de Entrada, mas carreguei minhas malhas e criei layouts antes de criar sombreadores. O que devo fazer?
Uma solução é alternar a ordem e carregar sombreadores antes de carregar malhas. No entanto, isso é muito mais fácil de dizer do que fazer. Você sempre pode criar os Layouts de Entrada sob demanda quando necessário pelo aplicativo. Você precisará manter uma versão da assinatura do sombreador ao redor. Você deve criar um hash com base no layout do sombreador e do buffer e criar apenas o Layout de Entrada se um correspondente ainda não existir.
Desenhar Chamadas
Qual é o meu limite de chamadas de desenho para D3D10 atingir 60 Hz? 30 Hz?
O Direct3D 9 tinha uma limitação no número de chamadas de desenho devido ao custo da CPU por chamada de desenho. No Direct3D 10, o custo de cada chamada de sorteio foi reduzido. No entanto, não há mais uma correlação definitiva entre chamadas de desenho e taxas de quadros. Como as chamadas de desenho geralmente exigem muitas chamadas de suporte (atualizações constantes de buffer, associações de textura, configuração de estado e assim por diante) o impacto da taxa de quadros da API agora depende mais do uso geral da API em vez de simplesmente desenhar contagens de chamadas.
Recursos
Qual tipo de uso de recurso devo usar para quais operações?
Use a seguinte folha de referências:
- A CPU atualiza o recurso mais de uma vez por quadro: D3D10_USAGE_DYNAMIC
- A CPU atualiza o recurso menos de uma vez por quadro: D3D10_USAGE_DEFAULT
- A CPU não atualiza o recurso: D3D10_USAGE_IMMUTABLE
- A CPU precisa ler o recurso: D3D10_USAGE_STAGING
Como os buffers constantes sempre devem ser atualizados com frequência, eles não estão em conformidade com a "folha de referências". Para quais tipos de recursos usar para buffers constantes, consulte a seção Buffers constantes .
O que aconteceu com DrawPrimitiveUP e DrawIndexedPrimitiveUP?
Eles se foram na D3D10. Para geometria dinâmica, use um buffer de D3D10_USAGE_DYNAMIC grande. No início do quadro, mapeie-o com D3D10_MAP_WRITE_DISCARD. Para cada chamada de desenho subsequente, avance o ponteiro de gravação após a posição dos vértices desenhados anteriormente e mapeie o buffer com D3D10_MAP_WRITE_NO_OVERWRITE. Se você estiver próximo ao final do buffer antes do final do quadro, encapsule o ponteiro de gravação ao redor do início e mapeie com D3D10_MAP_WRITE_DISCARD.
Posso escrever índices de 16 bits e índices de 32 bits no mesmo buffer de geometria dinâmica?
Sim, você pode, mas isso pode incorrer em uma penalidade de desempenho em determinado hardware. É mais seguro criar buffers separados para dados de índice dinâmicos de 16 bits e dados de índice de 32 bits.
Como fazer ler dados de volta da GPU para a CPU?
Você deve usar um recurso de preparo. Copie os dados do recurso de GPU para o recurso de preparo usando CopyResource. Mapeie o recurso de preparo para ler os dados.
Meu aplicativo dependia da funcionalidade StretchRect.
Como esse era essencialmente um wrapper para a funcionalidade básica do Direct3D, ele foi removido da API. Parte da funcionalidade StretchRect foi movida para D3DX10LoadTextureFromTexture. Para conversões de formato e texturas de cópia, D3DX10LoadTextureFromTexture pode fazer o trabalho. No entanto, operações como a conversão de um tamanho para outro provavelmente exigirão uma operação de renderização em textura no aplicativo.
Não há deslocamentos ou tamanhos em chamadas de mapa para recursos. Eles estavam lá em Chamadas de bloqueio no Direct3D 9; Por que eles mudaram?
Os deslocamentos e tamanhos em chamadas de bloqueio no Direct3D 9 eram basicamente desordens de API e muitas vezes ignorados pelo driver. Os deslocamentos devem ser calculados pelo aplicativo do ponteiro retornado na chamada mapa.
Profundidade como Textura
O que é mais rápido? Usar profundidade como textura ou profundidade de escrita para alfa e ler isso?
Isso é específico do aplicativo e do hardware. Use qualquer um que salve a maior largura de banda. Se você já estiver usando vários destinos de renderização e tiver um canal extra, gravar profundidade do sombreador poderá ser uma solução melhor. Além disso, gravar profundidade em alfa ou em outro destino de renderização permite que você escreva valores de profundidade linear que podem acelerar os cálculos que precisam acessar o buffer de profundidade.
Posso ter uma textura associada como uma entrada E associada como uma textura de estêncil de profundidade, desde que eu desabilite as gravações de profundidade?
Não na D3D10.
MSAA
Posso resolve uma textura de estêncil de profundidade MSAA?
Não na D3D10. No entanto, você pode amostrar amostras individuais da textura MSAA. Consulte a seção HLSL para obter detalhes.
Por que meu aplicativo falha assim que eu habilite o MSAA?
Verifique se você está habilitando uma contagem de exemplos msaa e um número de qualidade que, na verdade, são enumerados pelo driver.
Falhas
Meu aplicativo falha na D3D10 ou no driver e não sei por quê.
A primeira etapa é habilitar o runtime de depuração (D3D10_CREATE_DEVICE_DEBUG sinalizador passado para D3D10CreateDevice). Isso exporá os erros mais comuns como saída de depuração.
O PIX falha quando tento usar meu aplicativo com ele.
A primeira etapa é habilitar o runtime de depuração (D3D10_CREATE_DEVICE_DEBUG sinalizador passado para D3D10CreateDevice). O PIX tem uma probabilidade muito maior de falhar se a saída de depuração não for limpo.
Meu jogo fica sem espaço de endereço virtual no Vista de 32 bits em D3D10. Ele não tem problemas no D3D9.
Houve alguns problemas com o D3D10 e o espaço de endereço virtual. Isso foi corrigido em KB940105. Se isso não corrigir o problema, verifique se você não está criando mais recursos que podem ser mapeados (bloqueados) em D3D10 do que você estava criando em D3D9. Pense também na portabilidade para 64 bits, pois isso se tornará mais prevalente no futuro.
Renderização predefinida
Usei a renderização predefinida (com base nos resultados da consulta de oclusão). Por que meu aplicativo ainda tem a mesma velocidade?
Primeiro, verifique se a renderização que você gostaria de ignorar é, na verdade, o gargalo do aplicativo. Se não for o gargalo, ignorar a renderização não ajudará na taxa de quadros.
Em segundo lugar, verifique se o tempo suficiente passou entre o problema da consulta e a renderização que você deseja predicar. Se a consulta não tiver sido concluída no momento em que a chamada de renderização atingir a GPU, a renderização ocorrerá mesmo assim.
Em terceiro lugar, a precação ignora apenas determinadas chamadas. As chamadas ignoradas são Draw, Clear, Copy, Update, ResolveSubresource e GenerateMips. A configuração de estado, a configuração de IA, o Mapa e a criação de chamadas não respeitam a precação. Se houver muitas chamadas de configuração de estado em torno da chamada de desenho a ser predefinida, esses estados ainda serão definidos.
Sombreador de geometria
Devo usar o sombreador de geometria para mosaico meu (inserir alguma coisa aqui)?
Não. O sombreador de geometria NÃO deve ser usado para mosaico.
Posso usar o sombreador de geometria para criar geometria?
Sim, em cenários muito limitados. O sombreador de geometria nas partes D3D10 (2008) atuais não está equipado para lidar com muita expansão. Isso pode mudar no futuro. Os fornecedores de cartão de vídeo podem ter um caminho especial para uma a quatro expansões devido ao hardware de sprite de ponto existente. Qualquer outra expansão teria que ser muito limitada. As amostras de ParticlesGS e PipesGS atingem altas taxas de quadros fazendo apenas expansão limitada. Apenas alguns pontos são expandidos por quadro.
Para que devo usar o sombreador de geometria?
Qualquer coisa que exija operações em uma primitiva inteira, como detecção de silhueta, coordenadas barycentricas e assim por diante. Use-o também para selecionar a fatia de uma matriz de destino de renderização para a qual enviar primitivos.
Posso gerar quantidades variáveis de geometria do sombreador de geometria?
Sim, mas isso pode causar problemas de desempenho. Veja o exemplo de saída de 1 ponto para uma invocação e 4 pontos para outra. Ao se ajustar às diretrizes de expansão, isso pode fazer com que os threads de sombreador de geometria sejam executados em série.
Como o D3D10 sabe como gerar índices de adjacência para minha malha? Ou, por que o D3D10 não é renderizado corretamente quando especifique que o sombreador de geometria precisa de informações de adjacência.
As informações de adjacência não são criadas por D3D10, mas pelo aplicativo. Os índices de adjacência são gerados pelo aplicativo e devem conter seis índices por primitivo; dos seis, os índices numerados ímpares são os vértices adjacentes à borda. ID3DX10Mesh::GenerateAdjacencyAndPointsReps pode ser usado para gerar esses dados.
HLSL
As instruções inteiras e bit a bit estão lentas?
Eles podem ser. Vários cartões D3D10 podem ser capazes apenas de emitir operações de inteiro em um subconjunto das unidades de ALU disponíveis. Isso é altamente dependente do hardware. Consulte seu fornecedor de hardware individual para obter recomendações sobre como lidar com operações de inteiro nesse hardware específico. Além disso, tenha muito cuidado com conversões entre tipos.
O que aconteceu com o VPOS?
Se você declarar uma entrada para o sombreador de pixel como SV_POSITION, obterá o mesmo comportamento que declará-la como VPOS.
Como fazer amostrar uma textura MSAA?
No sombreador, declare sua textura como Texture2DMS. Em seguida, você pode buscar exemplos individuais usando os métodos sample do objeto Texture2DMS.
Como fazer saber se uma variável de sombreador em um buffer constante realmente é usada?
Examine o struct de D3D10_SHADER_VARIABLE_DESC refletido para essa variável. UFlags deve ter o sinalizador D3D10_SVF_USED definido.
Como fazer saber se uma variável de sombreador em um buffer constante realmente está usando FX10?
Atualmente, isso não é possível usando FX10.
Não tenho controle sobre buffers constantes que o FX10 cria. Como eles são criados e atualizados?
Todos os buffers constantes gerenciados pelo FX10 são criados como D3D10_USAGE_DEFAULT recursos e são atualizados usando UpdateSubresource. Como o FX10 mantém um repositório de backup de todos os dados constantes, UpdateSubresource é a melhor abordagem para atualizá-los.
Como fazer emular o pipeline de funções fixas usando sombreadores?
Confira Exemplo de FixedFuncEMU.
Devo usar as novas dicas do compilador \[unroll\], \[loop\], \[branch\]e assim por diante?
Em geral, não. O compilador geralmente tentará as duas maneiras e escolherá a mais rápida. Em alguns casos, pode ser necessário usar [cancelar registro], por exemplo, quando uma busca de textura dentro de um loop precisa de acesso a um gradiente.
A precisão parcial faz alguma diferença em D3D10? Posso especificar a precisão parcial no meu HLSL D3D9, mas não no meu HLSL D3D10.
Todas as operações D3D10 são especificadas para serem executadas com precisão de ponto flutuante de 32 bits. Portanto, a precisão parcial não deve fazer nenhuma diferença em D3D10.
Em D3D9, eu poderia fazer a filtragem de sombra de PCF HW associando um buffer de profundidade como uma textura e usando instruções tex2d hlsl regulares. Como fazer fazer isso no D3D10?
Você precisa usar um estado de amostra de comparação e usar instruções SampleCmp.
Como esse registro palavra-chave funciona no D3D10?
O registro palavra-chave em D3D10 agora se aplica a qual slot um recurso específico está associado. Nesse caso, o recurso pode ser um Buffer (constante ou não), Textura ou Sampler.
- Para buffers constantes, use a sintaxe: register(bN), em que N é o slot de entrada (0-15)
- Para texturas, use a sintaxe: register(tN), em que N é o slot de entrada (0-127)
- Para exemplos, use a sintaxe: register(sN), em que N é o slot de entrada (0-127)
Como fazer colocar uma variável dentro de um buffer constante se o registro for usado apenas para especificar onde associar o buffer inteiro?
Use o palavra-chave packoffset. O argumento para packoffset está na forma de c[0-4095]. [x,y,z,w]. Por exemplo:
cbuffer cbLotsOfEmptySpace
{
float IWaste2Floats : packoffset(c0.z);
float4 IWasteMore : packoffset(c13);
};
Nesse buffer constante, IWaste2Floats é colocado no terceiro float (12º byte) no buffer constante. IWasteMore é colocado no 13º float4 ou 52º float no buffer constante.