Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
FontCacheManager.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 
6 using SiliconStudio.Core;
7 using SiliconStudio.Core.Mathematics;
8 
9 namespace SiliconStudio.Paradox.Graphics.Font
10 {
11  /// <summary>
12  /// Represent a GPU cache of font characters
13  /// </summary>
14  internal class FontCacheManager : ComponentBase
15  {
16  private readonly FontSystem system;
17 
18  private readonly List<Texture2D> cacheTextures = new List<Texture2D>();
19  private readonly LinkedList<CharacterSpecification> cachedCharacters = new LinkedList<CharacterSpecification>();
20  private readonly GuillotinePacker packer = new GuillotinePacker();
21 
22  /// <summary>
23  /// The textures containing the cached characters on the GPU.
24  /// </summary>
25  public IReadOnlyList<Texture2D> Textures { get; private set; }
26 
27  public FontCacheManager(FontSystem system, int textureDefaultSize = 1024)
28  {
29  this.system = system;
30  Textures = cacheTextures;
31 
32  // create the cache textures
33  var newTexture = Texture2D.New(system.GraphicsDevice, textureDefaultSize, textureDefaultSize, PixelFormat.R8_UNorm);
34  cacheTextures.Add(newTexture);
35  newTexture.Reload = ReloadCache;
36  ClearCache();
37  }
38 
39  private void ReloadCache(GraphicsResourceBase graphicsResourceBase)
40  {
41  foreach (var cacheTexture in cacheTextures)
42  cacheTexture.Recreate();
43 
44  ClearCache();
45  }
46 
47  /// <summary>
48  /// Remove all the currently cached characters from the cache.
49  /// </summary>
50  public void ClearCache()
51  {
52  foreach (var character in cachedCharacters)
53  character.IsBitmapUploaded = false;
54  cachedCharacters.Clear();
55 
56  packer.Clear(cacheTextures[0].Width, cacheTextures[0].Height);
57  }
58 
59  /// <summary>
60  /// Upload a character's bitmap into the current cache.
61  /// </summary>
62  /// <param name="character">The character specifications corresponding to the bitmap</param>
63  public void UploadCharacterBitmap(CharacterSpecification character)
64  {
65  if(character.Bitmap == null)
66  throw new ArgumentNullException("character");
67 
68  if(character.IsBitmapUploaded)
69  throw new InvalidOperationException("The character '"+character.Character+"' upload has been requested while its current glyph is valid.");
70 
71  var targetSize = new Int2(character.Bitmap.Width, character.Bitmap.Rows);
72  if (!packer.Insert(targetSize.X, targetSize.Y, ref character.Glyph.Subrect))
73  {
74  // not enough space to place the new character -> remove less used characters and try again
75  RemoveLessUsedCharacters();
76  if (!packer.Insert(targetSize.X, targetSize.Y, ref character.Glyph.Subrect))
77  {
78  // memory is too fragmented in order to place the new character -> clear all the characters and restart.
79  ClearCache();
80  if (!packer.Insert(targetSize.X, targetSize.Y, ref character.Glyph.Subrect))
81  throw new InvalidOperationException("The rendered character is too big for the cache texture");
82  }
83  }
84  // updload the bitmap on the texture (if the size in the bitmap is not null)
85  if (character.Bitmap.Rows != 0 && character.Bitmap.Width != 0)
86  {
87  var dataBox = new DataBox(character.Bitmap.Buffer, character.Bitmap.Pitch, character.Bitmap.Pitch * character.Bitmap.Rows);
88  var region = new ResourceRegion(character.Glyph.Subrect.Left, character.Glyph.Subrect.Top, 0, character.Glyph.Subrect.Right, character.Glyph.Subrect.Bottom, 1);
89  system.GraphicsDevice.UpdateSubresource(cacheTextures[0], 0, dataBox, region);
90  }
91 
92  // update the glyph data
93  character.IsBitmapUploaded = true;
94  character.Glyph.BitmapIndex = 0;
95  }
96 
97  /// <summary>
98  /// Remove all the character that haven't been used for the given amount of frames
99  /// </summary>
100  private void RemoveLessUsedCharacters(int frameCount = 5)
101  {
102  var limitFrame = system.FrameCount - frameCount;
103  var currentNode = cachedCharacters.Last;
104  while (currentNode != null && currentNode.Value.LastUsedFrame < limitFrame)
105  {
106  currentNode.Value.IsBitmapUploaded = false;
107  packer.Free(ref currentNode.Value.Glyph.Subrect);
108  currentNode = currentNode.Previous;
109  cachedCharacters.RemoveLast();
110  }
111  }
112 
113  protected override void Destroy()
114  {
115  base.Destroy();
116 
117  foreach (var cacheTexture in cacheTextures)
118  cacheTexture.Dispose();
119 
120  cacheTextures.Clear();
121  cachedCharacters.Clear();
122  }
123 
124  public void NotifyCharacterUtilization(CharacterSpecification character)
125  {
126  character.LastUsedFrame = system.FrameCount;
127 
128  if(character.ListNode.List != null)
129  cachedCharacters.Remove(character.ListNode);
130  cachedCharacters.AddFirst(character.ListNode);
131  }
132  }
133 }
ComponentBase.Destroy() event.
Base class for a framework component.
SharpDX.DirectWrite.Font Font
Represents a three dimensional mathematical vector.
Definition: Int2.cs:41