Hello,
Tout d'abord, mes connaissances en C# sont assez limitées.
J'ai un petit utilitaire pour faire un atlas à partir d'une font. Je l'ai codé en C++ (avec la SFML), ça marche pas trop mal.
Créer une GUI en C++ c'est plutôt chiant, du coup j'ai recoder ça en C# (copier / coller et corriger les erreurs de syntaxe ), jusque là pas de problèmes.
Mais rapidement je me suis heurté à de gros problèmes de gestion de mémoire en C# (l’ironie...).
Basiquement j'ai quelque chose du genreClairement le code n'est pas optimal (pas besoin d'essayer de créer tous les atlas avec toutes les allocations de RenderTexture que ça représente).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 public class Atlas { public static Image Pack(string fontName, uint fontSize, string charToDraw, uint atlasSize=4096) { // Image est SFML.Graphics.Image // utilisation de SFML.Graphics.RenderTexture pour créer l'atlas // return null si atlas impossible à créer (les caractères ne rentre pas dans la taille demandée) // return l'image sinon } public class PackResult { public Image img; public uint fontSize; } public static PackResult PackMaxSize(string fontName, string charToDraw, uint maxFontSize=1000, uint atlasSize=4096) { // recherche dichotomique de la taille maximale possible // 10 appels maximum à Pack pour maxFontSize=1024 par exemple } }
Si j'essaie de créer plusieurs atlas, SFML fini par throw une exception : je remplis la VRAM parce que le GC ne juge pas nécessaire de faire le ménage.
A priori la solution est d'utiliser un using(var foo = new Foo()) { } pour chaque ressource dont je dois contrôler la durée de vie (donc strict minimum toutes les classes SFML qui allouent quelque chose en VRAM).
Çà marche, mais j'ai tellement de using(var foo = new Foo()) { } que ça en devient ridicule : un new = un using(...) { }.
Ya une solution à ce genre de problème ? Peut être avec une classe contenant les variables locales d'une fonction ?
Par exempleMais... ça me semble être une solution assez mauvaise (créer une classe pour chaque fonction...), et surtout ça semble être une façon de faire qui veut trop se caler sur la façon de "penser C++".
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 private class PackLocalVars { public Font font; public Text text; public Atlas atlas; public RenderTexture rTex; } public static Image Pack(string fontName, uint fontSize, string charToDraw, uint atlasSize=4096) { using (var locals = new PackLocalVars()) { locals.rTex = new RenderTexture(...); // ... return locals.rTex.Texture.copyToImage(); } // locals.rTex.Dispose() sera bien appelé ici ? Il faut que PackLocalVars implémente IDisposable ? }
Bref, une bonne solution existe à ce problème ?
Question bonus, pourquoi ça ne marche pas ? -> La conso RAM / VRam explose et j'ai la même exception de lancée.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 public static PackResult PackMaxSize(string fontName, string charToDraw, uint maxFontSize=1000, uint atlasSize=4096) { var ret = PackResult(); while(...) { System.GC.Collect(); uint fontSize = ...; Image img = Pack(...); if(img != null) { ret.img = img; ret.fontSize = fontSize; } } return ret; }
Partager