introduce loadingImages & add a lock around image load/unload state

This commit is contained in:
Colin McMillen 2023-07-28 13:07:47 -04:00
parent ad598e68a5
commit 33f6ee739e

View File

@ -571,6 +571,8 @@ public class Game : GameWindow {
List<Photo> allPhotos = new(); List<Photo> allPhotos = new();
List<Photo> photos = new(); List<Photo> photos = new();
HashSet<Photo> loadedImages = new(); HashSet<Photo> loadedImages = new();
HashSet<Photo> loadingImages = new();
readonly object loadedImagesLock = new();
int photoIndex = 0; int photoIndex = 0;
int ribbonIndex = 0; int ribbonIndex = 0;
Shader shader = new(); Shader shader = new();
@ -777,10 +779,10 @@ public class Game : GameWindow {
// Load photos from a directory. // Load photos from a directory.
// string[] files = Directory.GetFiles(@"c:\users\colin\desktop\photos-test\"); // string[] files = Directory.GetFiles(@"c:\users\colin\desktop\photos-test\");
string[] files = Directory.GetFiles(@"c:\users\colin\pictures\photos\2023\07\14\"); // string[] files = Directory.GetFiles(@"c:\users\colin\pictures\photos\2023\07\14\");
// string[] files = Directory.GetFiles(@"G:\DCIM\100EOSR6\"); // string[] files = Directory.GetFiles(@"G:\DCIM\100EOSR6\");
// string[] files = Directory.GetFiles(@"C:\Users\colin\Pictures\photos\2018\06\23"); // string[] files = Directory.GetFiles(@"C:\Users\colin\Pictures\photos\2018\06\23");
// string[] files = Directory.GetFiles(@"C:\Users\colin\Desktop\Germany all\104D7000"); string[] files = Directory.GetFiles(@"C:\Users\colin\Desktop\Germany all\104D7000");
// string[] files = Directory.GetFiles(@"C:\Users\colin\Desktop\many-birds\"); // string[] files = Directory.GetFiles(@"C:\Users\colin\Desktop\many-birds\");
for (int i = 0; i < files.Count(); i++) { for (int i = 0; i < files.Count(); i++) {
@ -809,43 +811,62 @@ public class Game : GameWindow {
base.OnUnload(); base.OnUnload();
} }
private async void LoadAndUnloadImagesAsync() { private void UnloadImages() {
int minLoadedImage = Math.Max(0, photoIndex - 20); // Unload images that haven't been touched in a while.
int maxLoadedImage = Math.Min(photoIndex + 20, photos.Count - 1);
// First, unload images that haven't been touched in a while.
// FIXME: also cancel any of these if they still have an in-progress loading task?
// FIXME: keep around thumbnail-sized textures? // FIXME: keep around thumbnail-sized textures?
while (loadedImages.Count > 60) { lock (loadedImagesLock) {
long earliestTime = long.MaxValue; while (loadedImages.Count > 60) {
Photo? earliest = null; long earliestTime = long.MaxValue;
foreach (Photo photo in loadedImages) { Photo? earliest = null;
if (photo.LastTouch < earliestTime) { foreach (Photo photo in loadedImages) {
earliest = photo; if (photo.LastTouch < earliestTime) {
earliestTime = photo.LastTouch; earliest = photo;
earliestTime = photo.LastTouch;
}
}
if (earliest != null) {
// Console.WriteLine($"loadedImages.Count: {loadedImages.Count}, evicting {earliest.Filename} @ {earliestTime}");
// TODO: we have to free textures on the GL thread, but could we do that async'ly to keep the UI responsive?
earliest.Unload();
loadedImages.Remove(earliest);
} }
} }
if (earliest != null) { }
Console.WriteLine($"loadedImages.Count: {loadedImages.Count}, evicting {earliest.Filename} @ {earliestTime}"); }
// TODO: we have to free textures on the GL thread, but could we do that async'ly to keep the UI responsive?
earliest.Unload(); private async void LoadImagesAsync() {
loadedImages.Remove(earliest); foreach (Photo p in loadingImages) {
if (p.Loaded) {
lock (loadedImagesLock) {
loadedImages.Add(p);
loadingImages.Remove(p);
}
} }
} }
// Then, start loading any images that are in our window but not yet loaded. // Start loading any images that are in our window but not yet loaded.
int minLoadedImage = Math.Max(0, photoIndex - 20);
int maxLoadedImage = Math.Min(photoIndex + 20, photos.Count - 1);
List<Photo> toLoad = new();
for (int i = minLoadedImage; i <= maxLoadedImage; i++) { for (int i = minLoadedImage; i <= maxLoadedImage; i++) {
if (!loadedImages.Contains(photos[i])) { lock (loadedImagesLock) {
Console.WriteLine("loading " + i); if (!loadedImages.Contains(photos[i]) && !loadingImages.Contains(photos[i])) {
loadedImages.Add(photos[i]); Console.WriteLine("loading " + i);
await Task.Run( () => { photos[i].LoadAsync(); }); loadingImages.Add(photos[i]);
toLoad.Add(photos[i]);
}
} }
} }
foreach (Photo p in toLoad) {
await Task.Run( () => { p.LoadAsync(); });
}
} }
protected override void OnRenderFrame(FrameEventArgs e) { protected override void OnRenderFrame(FrameEventArgs e) {
base.OnRenderFrame(e); base.OnRenderFrame(e);
fpsCounter.Update(); fpsCounter.Update();
LoadAndUnloadImagesAsync(); UnloadImages();
LoadImagesAsync();
GL.Clear(ClearBufferMask.ColorBufferBit); GL.Clear(ClearBufferMask.ColorBufferBit);
GL.BindBuffer(BufferTarget.ArrayBuffer, VertexBufferObject); GL.BindBuffer(BufferTarget.ArrayBuffer, VertexBufferObject);