A game framework written with osu! in mind.
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2// See the LICENCE file in the repository root for full licence text.
3
4using System.Collections.Generic;
5using System.Diagnostics;
6using System.Threading;
7using JetBrains.Annotations;
8using osu.Framework.IO.Stores;
9using osuTK.Graphics.ES30;
10
11namespace osu.Framework.Graphics.Textures
12{
13 /// <summary>
14 /// A texture store that bypasses atlasing and removes textures from memory after dereferenced by all consumers.
15 /// </summary>
16 public class LargeTextureStore : TextureStore
17 {
18 private readonly object referenceCountLock = new object();
19 private readonly Dictionary<string, TextureWithRefCount.ReferenceCount> referenceCounts = new Dictionary<string, TextureWithRefCount.ReferenceCount>();
20
21 public LargeTextureStore(IResourceStore<TextureUpload> store = null, All filteringMode = All.Linear)
22 : base(store, false, filteringMode, true)
23 {
24 }
25
26 protected override bool TryGetCached(string lookupKey, out Texture texture)
27 {
28 lock (referenceCountLock)
29 {
30 if (base.TryGetCached(lookupKey, out var tex))
31 {
32 texture = createTextureWithRefCount(lookupKey, tex);
33 return true;
34 }
35
36 texture = null;
37 return false;
38 }
39 }
40
41 protected override Texture CacheAndReturnTexture(string lookupKey, Texture texture)
42 {
43 lock (referenceCountLock)
44 return createTextureWithRefCount(lookupKey, base.CacheAndReturnTexture(lookupKey, texture));
45 }
46
47 private TextureWithRefCount createTextureWithRefCount([NotNull] string lookupKey, [CanBeNull] Texture baseTexture)
48 {
49 if (baseTexture == null)
50 return null;
51
52 lock (referenceCountLock)
53 {
54 if (!referenceCounts.TryGetValue(lookupKey, out TextureWithRefCount.ReferenceCount count))
55 referenceCounts[lookupKey] = count = new TextureWithRefCount.ReferenceCount(referenceCountLock, () => onAllReferencesLost(baseTexture));
56
57 return new TextureWithRefCount(baseTexture.TextureGL, count);
58 }
59 }
60
61 private void onAllReferencesLost(Texture texture)
62 {
63 Debug.Assert(Monitor.IsEntered(referenceCountLock));
64
65 referenceCounts.Remove(texture.LookupKey);
66 Purge(texture);
67 }
68 }
69}