Je n'ai pas traité le problème spécifique que vous avez rencontré, mais j'ai trouvé que les pools de textures étaient extrêmement utiles dans OpenGL pour obtenir des résultats efficaces sans avoir à y penser beaucoup. Dans mon cas, le problème était que je ne pouvais pas utiliser la même texture pour une entrée dans un shader différé que la texture utilisée pour sortir les résultats. Pourtant, je voulais souvent faire exactement cela:
// Make the texture blurry.
blur(texture);
Pourtant, au lieu que j'avais pour créer 11 textures différentes avec différentes résolutions et d'avoir à échanger entre eux des entrées et des sorties pour les shaders de flou horizontal/vertical avec les organisations confessionnelles pour obtenir un flou à l'aspect décent. Je n'ai jamais vraiment aimé la programmation GPU car certains des cas de gestion d'état les plus complexes que j'ai rencontrés étaient souvent là. Il me semblait incroyablement mauvais que je devais aller à la planche à dessin juste pour comprendre comment minimiser le nombre de textures allouées en raison de cette exigence fondamentale que les entrées de texture pour les shaders ne puissent pas être utilisées comme sorties de texture.
J'ai donc créé un pool de texture et OMG, ça a tellement simplifié les choses!Il a fait en sorte que je puisse simplement créer des objets de texture temporaires à gauche et à droite et ne pas m'inquiéter car la destruction de l'objet de texture n'appelle pas réellement glDeleteTextures
, il les renvoie simplement au pool. J'ai donc pu enfin faire:
blur(texture);
... comme je le voulais depuis toujours. Et pour une raison amusante, quand j'ai commencé à utiliser la piscine de plus en plus, elle a accéléré les taux de trame. Je suppose que même avec toute la pensée que j'ai mise en minimisant le nombre de textures allouées, j'allais toujours allouer plus que nécessaire de manière à éliminer le pool (notez que l'exemple du monde réel fait bien plus que du flou, y compris DOF, bloom, hipass, lowpass, CMAA, etc, et le code GLSL est en fait généré à la volée sur la base d'un langage de programmation visuel que les utilisateurs peuvent utiliser pour créer de nouveaux shaders à la volée).
Donc, je recommande vraiment de commencer par explorer cette idée. Il semble que ce serait utile pour votre problème. Dans mon cas, je ceci:
struct GlTextureDesc
{
...
};
... et c'est une structure assez lourde étant donné le nombre de paramètres texture, nous pouvons spécifier (format de pixels, le nombre de composantes de couleur, niveau LOD, largeur, hauteur, etc., etc. .).
Pourtant, la structure est comparable et lavable et finit par être utilisée comme une clé dans une table de hachage (comme unordered_multimap
) avec la poignée de texture réelle comme valeur associée.
Cela nous permet de faire alors ceci:
// Provides a pool of textures. This allows us to conveniently rapidly create,
// and destroy texture objects without allocating and freeing an excessive number
// of textures.
class GlTexturePool
{
public:
// Creates an empty pool.
GlTexturePool();
// Cleans up any textures which haven't been accessed in a while.
void cleanup();
// Allocates a texture with the specified properties, retrieving an existing
// one from the pool if available. The function returns a handle to the
// allocated texture.
GLuint allocate(const GlTextureDesc& desc);
// Returns the texture with the specified key and handle to the pool.
void free(const GlTextureDesc& desc, GLuint texture);
private:
...
};
à quel point nous pouvons créer des objets temporaires de texture gauche et à droite sans se soucier des appels excessifs à glTexImage2D
et glDeleteTextures
.Je trouve cela extrêmement utile. Enfin, notons que cleanup
fonctionne ci-dessus. Lorsque je stocke des textures dans la table de hachage, je leur mets un horodatage (en utilisant le système en temps réel). Périodiquement, j'appelle cette fonction de nettoyage qui analyse ensuite les textures dans la table de hachage et vérifie l'horodatage. Si une certaine période de temps s'est écoulée alors qu'ils sont juste assis au ralenti dans la piscine (disons 8 secondes), j'appelle glDeleteTextures
et les retire de la piscine. J'utilise un thread séparé avec une variable de condition pour créer une liste de textures à supprimer la prochaine fois qu'un contexte valide est disponible en analysant périodiquement la table de hachage, mais si votre application est entièrement monothread, vous pouvez invoquer ce nettoyage Fonctionne toutes les quelques secondes dans votre boucle principale. Cela dit, je travaille en VFX qui n'a pas des exigences en temps réel aussi serrées que, disons, les jeux AAA. Il y a plus d'accent sur le rendu hors ligne dans mon domaine et je suis loin d'un assistant GPU. Il pourrait y avoir de meilleurs moyens de s'attaquer à ce problème. Cependant, j'ai trouvé très utile de commencer avec ce pool de texture et je pense qu'il pourrait être utile dans votre cas aussi. Et c'est assez trivial à mettre en œuvre (il m'a juste pris une demi-heure environ). Cela pourrait encore finir par allouer et supprimer des lots et beaucoup de textures si les tailles de texture et les formats et les paramètres que vous demandez d'allouer/free sont partout. Là, il pourrait aider à unifier les choses un peu, comme au moins en utilisant POT (puissance de deux) tailles et ainsi de suite et de décider sur un nombre minimum de formats de pixels à utiliser. Dans mon cas ce n'était pas vraiment un problème car je n'utilise qu'un seul format de pixel et la majorité des temporaires de texture que je voulais créer sont exactement la taille d'une fenêtre agrandie au plafond POT. Comme pour les FBO, je ne sais pas comment ils aident votre problème immédiat avec l'allocation/la libération excessive de texture non plus.Je les utilise principalement pour l'ombrage différé pour effectuer un post-traitement pour des effets tels que DOF après avoir rendu la géométrie en plusieurs passes d'une manière de type compositing appliquée aux textures 2D qui en résultent. J'utilise les FBO pour cela naturellement mais je ne peux pas penser à la façon dont les FBO réduisent immédiatement le nombre de textures que vous devez allouer/désallouer, sauf si vous pouvez simplement utiliser une grande texture avec un FBO et lui rendre plusieurs textures d'entrée vers une sortie hors écran texture. Dans ce cas, les FBO ne seraient pas directement en mesure de créer une texture énorme dont les sections peuvent être utilisées comme entrées/sorties au lieu de beaucoup plus petites.