Estava investigando uma queda muito pesada de FPS na Skill Birds (Chaotic Diseier / Dark Lord). Em algumas situações, essa skill praticamente derrubava o jogo sozinho.
Inicialmente parecia que o problema poderia ser a quantidade de partículas ou a geometria dos efeitos, mas não era nada disso.
O problema estava na forma como o sistema estava enviando as partículas para renderização.
Basicamente, o sistema estava fazendo um "flush" no batch praticamente a cada quad renderizado.
Para explicar de forma simples: o batch serve justamente para juntar vários desenhos parecidos e enviar tudo de uma vez para a placa de vídeo. Só que, nesse caso, o estado de blend estava sendo alterado várias vezes sem necessidade.
Então acontecia algo parecido com isso para uma única partícula:
EnableAlphaBlend(); // muda o estado e gera flush
EnableAlphaBlendMinus(); // muda novamente e gera outro flush
Ou seja, o próprio código se desfazia dentro da mesma
A solução foi identificar qual blend cada partícula realmente vai usar antes de desenhá-la.
Depois disso, as partículas passaram a ser organizadas primeiro pelo tipo de blend e, em seguida, pelos outros estados que também influenciam a renderização, como tipo, subtipo e textura.
Com isso, em vez de ficar alternando:
Blend normal
Blend minus
Blend normal
Blend minus
Blend normal
o sistema consegue agrupar melhor:
Todas com Blend normal
Todas com Blend minus
Todas com Blend3
Isso reduziu drasticamente a quantidade de flushes e draw calls.
Vou deixar abaixo o código que usei para fazer a correção, caso alguém queira acoplar na sua source

Importante: se o seu Main tiver Type/SubType customizados, confira os case do seu próprio RenderParticles e adicione eles no ParticleFinalBlend(). A lógica é a mesma: o blend que a partícula realmente usa precisa ser conhecido antes da renderização.
Se alguém quiser aplicar a mesma ideia em outros sistemas de efeito, vale procurar por situações onde o código fica alternando EnableAlphaBlend, EnableAlphaBlendMinus, EnableAlphaBlend3, etc. dentro do loop de renderização. É aí que normalmente começa esse tipo de problema de flush.