Se você só precisa de normais por face e se seus cabos de texto para uma face são estritamente 0/0, 0/1, 1/0, 1/1 (ou similares para se adequar ao seu layout), você pode construir um cubo com 8 verts e 30 (faixa com reinicialização) ou 36 (lista) índices. Busque os normais e os cabos de texto usando uma pesquisa de matriz constante baseada em SV_VertexID no seu sombreador de vértices.
Fazer isso significa que você nem precisa incluir cabos de texto ou normais no seu buffer de vértice, o que proporcionará ainda mais economia de memória.
Indo mais longe, você ainda pode ir até 24 verts por cubo, mas também usar instanciamento. Cada cubo teria um tamanho fixo no seu buffer de vértice (1x1x1) e você teria um fator de escala e uma posição (assumindo que seus cubos não giram, uma matriz se o fizer) como dados por instância. No caso não rotativo, você tem um custo único de 24 verts, mas cada cubo precisa apenas de 6 flutuadores para especificar completamente. No caso rotativo, você está olhando para 16 carros alegóricos, mas mesmo isso é uma economia substancial (nesse caso, é mais provável que você gargale o lado da CPU nas transformações de matriz - para o caso não rotativo que constrói uma matriz em tempo real seu sombreador de vértice - mesmo que seja feito por vértice, é tão estupidamente rápido que você nem precisa se preocupar com isso).
Para texturas por face, basta usar uma matriz de textura. Você precisa garantir que cada textura na matriz tenha o mesmo tamanho, é claro, e ainda precisará interromper o lote atual se a própria matriz precisar mudar, mas, caso contrário, ele fará o trabalho muito bem. Adicione um terceiro texcoord à sua definição de vértice, que define a fatia da matriz a ser usada para cada face.
Você não precisa de um GS com isso, e ele deve ser executado mais rapidamente do que usar um, pois ter o estágio de sombreador de geometria ativado imporá uma sobrecarga extra por si só.
Eu tenho código de referência no meu mecanismo que apenas desenha um monte de cubos usando esse método, e posso facilmente percorrer mais de 300.000 cubos enquanto ainda limpo 60 fps, em uma GPU relativamente baixa, e sem fazer mais nada para otimizar o processo . É certo que não os estou iluminando nem texturizando, mas tenho a mistura alfa ativada, o descarte da face posterior desativado e, em geral, se equilibra com a parte "não fazendo mais nada para otimizar", portanto, você deve ter uma idéia razoável do tipo de estimativa que você pode acertar com este método.