feat(app): add TextureCache for Surface→GL texture handle caching
This commit is contained in:
parent
5d35f4fe46
commit
cefc689ba8
1 changed files with 92 additions and 0 deletions
92
src/AcDream.App/Rendering/TextureCache.cs
Normal file
92
src/AcDream.App/Rendering/TextureCache.cs
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
// src/AcDream.App/Rendering/TextureCache.cs
|
||||
using AcDream.Core.Textures;
|
||||
using DatReaderWriter;
|
||||
using DatReaderWriter.DBObjs;
|
||||
using Silk.NET.OpenGL;
|
||||
|
||||
namespace AcDream.App.Rendering;
|
||||
|
||||
public sealed unsafe class TextureCache : IDisposable
|
||||
{
|
||||
private readonly GL _gl;
|
||||
private readonly DatCollection _dats;
|
||||
private readonly Dictionary<uint, uint> _handlesBySurfaceId = new();
|
||||
private uint _magentaHandle;
|
||||
|
||||
public TextureCache(GL gl, DatCollection dats)
|
||||
{
|
||||
_gl = gl;
|
||||
_dats = dats;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or upload the GL texture handle for a Surface id. Returns a
|
||||
/// 1x1 magenta fallback if the Surface or its RenderSurface chain is
|
||||
/// missing or uses an unsupported format.
|
||||
/// </summary>
|
||||
public uint GetOrUpload(uint surfaceId)
|
||||
{
|
||||
if (_handlesBySurfaceId.TryGetValue(surfaceId, out var h))
|
||||
return h;
|
||||
|
||||
var decoded = DecodeFromDats(surfaceId);
|
||||
h = UploadRgba8(decoded);
|
||||
_handlesBySurfaceId[surfaceId] = h;
|
||||
return h;
|
||||
}
|
||||
|
||||
private DecodedTexture DecodeFromDats(uint surfaceId)
|
||||
{
|
||||
var surface = _dats.Get<Surface>(surfaceId);
|
||||
if (surface is null)
|
||||
return DecodedTexture.Magenta;
|
||||
|
||||
var surfaceTexture = _dats.Get<SurfaceTexture>((uint)surface.OrigTextureId);
|
||||
if (surfaceTexture is null || surfaceTexture.Textures.Count == 0)
|
||||
return DecodedTexture.Magenta;
|
||||
|
||||
var rs = _dats.Get<RenderSurface>((uint)surfaceTexture.Textures[0]);
|
||||
if (rs is null)
|
||||
return DecodedTexture.Magenta;
|
||||
|
||||
return SurfaceDecoder.DecodeRenderSurface(rs);
|
||||
}
|
||||
|
||||
private uint UploadRgba8(DecodedTexture decoded)
|
||||
{
|
||||
uint tex = _gl.GenTexture();
|
||||
_gl.BindTexture(TextureTarget.Texture2D, tex);
|
||||
|
||||
fixed (byte* p = decoded.Rgba8)
|
||||
_gl.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
0,
|
||||
InternalFormat.Rgba8,
|
||||
(uint)decoded.Width,
|
||||
(uint)decoded.Height,
|
||||
0,
|
||||
PixelFormat.Rgba,
|
||||
PixelType.UnsignedByte,
|
||||
p);
|
||||
|
||||
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
||||
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||||
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
|
||||
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
|
||||
|
||||
_gl.BindTexture(TextureTarget.Texture2D, 0);
|
||||
return tex;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var h in _handlesBySurfaceId.Values)
|
||||
_gl.DeleteTexture(h);
|
||||
_handlesBySurfaceId.Clear();
|
||||
if (_magentaHandle != 0)
|
||||
{
|
||||
_gl.DeleteTexture(_magentaHandle);
|
||||
_magentaHandle = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue