Load pngs from cache

This commit is contained in:
Simon Lübeß
2024-05-20 13:35:37 +02:00
parent f0fc67db35
commit ffe8954b8d
4 changed files with 235 additions and 154 deletions
+13
View File
@@ -230,4 +230,17 @@ class AssetCache
return .Ok;
}
public Result<void> OpenFileStream(CachedAsset asset, FileStream fileStream)
{
if (asset == null)
return .Err;
Try!(fileStream.Close());
Try!(fileStream.Open(asset.FilePath, .Read, .Read));
fileStream.Position = asset.DataOffset;
return .Ok;
}
}
@@ -27,3 +27,8 @@ interface IAssetExporter
Result<void> Export(Stream stream, ProcessedResource processedObject, AssetExporterConfig config);
}
interface IProcessedAssetLoader
{
Result<Asset> Load(Stream stream);
}
@@ -5,6 +5,7 @@ using Bon;
using GlitchyEngine.Content;
using GlitchyEngine;
using GlitchyEngine.Renderer;
using GlitchyEngine.Math;
using static GlitchyEditor.Assets.Importers.LoadedTextureInfo;
namespace GlitchyEditor.Assets.Importers;
@@ -234,11 +235,20 @@ class TextureProcessorConfig : AssetProcessorConfig
[BonInclude]
private GenerateMipMaps _generateMipMaps;
[BonInclude]
private SamplerStateDescription _samplerStateDescription = .();
public GenerateMipMaps GenerateMipMaps
{
get => _generateMipMaps;
set => SetIfChanged(ref _generateMipMaps, value);
}
public SamplerStateDescription SamplerStateDescription
{
get => _samplerStateDescription;
set => SetIfChanged(ref _samplerStateDescription, value);
}
}
abstract class ProcessedResource
@@ -267,6 +277,8 @@ class ProcessedTexture : ProcessedResource
public int Height = -1;
public int Depth = -1;
public SamplerStateDescription SamplerStateDescription;
public override AssetType AssetType => .Texture;
public class TextureSurface
@@ -277,9 +289,11 @@ class ProcessedTexture : ProcessedResource
public int Depth;
public int MipLevel;
public int ArraySlice;
public int LinePitch;
public int SlicePitch;
[AllowAppend]
public this(int width, int height, int depth, Span<uint8> data, int mipLevel, int arraySlice)
public this(int width, int height, int depth, Span<uint8> data, int mipLevel, int arraySlice, int linePitch, int slicePitch)
{
uint8[] pixelData = append uint8[data.Length];
data.CopyTo(pixelData);
@@ -290,6 +304,8 @@ class ProcessedTexture : ProcessedResource
Depth = depth;
MipLevel = mipLevel;
ArraySlice = arraySlice;
LinePitch = linePitch;
SlicePitch = slicePitch;
}
public uint64 LoadRaw(int x, int y, int z, Format format, ComponentInfo component)
@@ -390,12 +406,14 @@ class TextureProcessor : IAssetProcessor
processedTexture.Height = importedTexture.TextureInfo.Height;
processedTexture.Depth = importedTexture.TextureInfo.Depth;
processedTexture.SamplerStateDescription = config.SamplerStateDescription;
processedTexture.SetSurfaceCount(importedTexture.TextureInfo.ArraySize, importedTexture.TextureInfo.MipMapCount);
for (LoadedSurface loadedSurface in importedTexture.Surfaces)
{
ProcessedTexture.TextureSurface surface = new .(loadedSurface.Width, loadedSurface.Height, loadedSurface.Depth,
loadedSurface.Data, loadedSurface.MipLevel, loadedSurface.ArrayIndex);
loadedSurface.Data, loadedSurface.MipLevel, loadedSurface.ArrayIndex, loadedSurface.Pitch, loadedSurface.SlicePitch);
processedTexture.Surfaces[loadedSurface.ArrayIndex, loadedSurface.MipLevel] = surface;
}
@@ -499,7 +517,9 @@ class TextureProcessor : IAssetProcessor
if (smallerLevel == null)
{
smallerLevel = new ProcessedTexture.TextureSurface(width, height, depth, new uint8[width * height * depth * pixelFormat.BitsPerPixel()], largerLevel.MipLevel + 1, largerLevel.ArraySlice);
smallerLevel = new ProcessedTexture.TextureSurface(width, height, depth,
new uint8[width * height * depth * pixelFormat.BitsPerPixel()], largerLevel.MipLevel + 1, largerLevel.ArraySlice,
-1, -1); // TODO!
}
// TODO: Kaiser mip maps?
@@ -556,6 +576,8 @@ class TextureExporter : IAssetExporter
Depth of larges mip-slice (4 bytes)
Array size (4 bytes)
Mip map levels (4 bytes)
Is Cubemap (1 byte)
Data Byte count (8 bytes)
Pixeldata
{
Array[0]: Mip[0] Mip[1] ... Mip[M]
@@ -573,6 +595,9 @@ class TextureExporter : IAssetExporter
Try!(stream.Write((uint32)processedTexture.Depth));
Try!(stream.Write((uint32)processedTexture.ArraySize));
Try!(stream.Write((uint32)processedTexture.MipMapCount));
Try!(stream.Write(processedTexture.IsCubeMap));
Try!(WriteSamplerStateDescription(stream, processedTexture.SamplerStateDescription));
for (int arraySlice < processedTexture.ArraySize)
{
@@ -600,28 +625,121 @@ class TextureExporter : IAssetExporter
if (validateDepth < 1)
validateDepth = 1;
Try!(stream.Write((uint32)slice.LinePitch));
Try!(stream.Write((uint32)slice.SlicePitch));
Try!(stream.Write((uint64)slice.PixelData.Count));
Try!(stream.TryWrite(slice.PixelData));
}
}
return .Ok;
}
}
class TextureLoader
{
public Result<Asset> Load(Stream data, AssetIdentifier assetIdentifier)
private Result<void> WriteSamplerStateDescription(Stream stream, SamplerStateDescription sampler)
{
Dimension dimension = Try!(data.Read<Dimension>());
Format pixelFormat = Try!(data.Read<Format>());
uint32 width = Try!(data.Read<uint32>());
uint32 height = Try!(data.Read<uint32>());
uint32 depth = Try!(data.Read<uint32>());
uint32 arraySize = Try!(data.Read<uint32>());
uint32 mipMapCount = Try!(data.Read<uint32>());
Try!(stream.Write(sampler.MinFilter));
Try!(stream.Write(sampler.MagFilter));
Try!(stream.Write(sampler.MipFilter));
Try!(stream.Write(sampler.FilterMode));
Try!(stream.Write(sampler.ComparisonFunction));
Try!(stream.Write(sampler.AddressModeU));
Try!(stream.Write(sampler.AddressModeV));
Try!(stream.Write(sampler.AddressModeW));
Try!(stream.Write(sampler.MipLODBias));
Try!(stream.Write(sampler.MipMinLOD));
Try!(stream.Write(sampler.MipMaxLOD));
Try!(stream.Write(sampler.MaxAnisotropy));
Try!(stream.Write(sampler.BorderColor));
return .Ok;
}
}
class TextureLoader : IProcessedAssetLoader
{
public Result<Asset> Load(Stream dataStream)
{
Dimension dimension = Try!(dataStream.Read<Dimension>());
Format pixelFormat = Try!(dataStream.Read<Format>());
uint32 width = Try!(dataStream.Read<uint32>());
uint32 height = Try!(dataStream.Read<uint32>());
uint32 depth = Try!(dataStream.Read<uint32>());
uint32 arraySize = Try!(dataStream.Read<uint32>());
uint32 mipMapCount = Try!(dataStream.Read<uint32>());
bool isCubemap = Try!(dataStream.Read<bool>());
return .Ok(null);
SamplerStateDescription sampler = Try!(ReadSampler(dataStream));
List<uint8[]> surfaceDatas = scope .(mipMapCount * arraySize);
defer { ClearAndDeleteItems!(surfaceDatas); }
TextureSliceData[] slices = scope TextureSliceData[mipMapCount * arraySize];
int index = 0;
for (int arraySlice < arraySize)
{
for (int mipSlice < mipMapCount)
{
uint32 linePitch = Try!(dataStream.Read<uint32>());
uint32 slicePitch = Try!(dataStream.Read<uint32>());
uint64 byteCount = Try!(dataStream.Read<uint64>());
uint8[] surfaceData = new uint8[byteCount];
Try!(dataStream.TryRead(surfaceData));
slices[index] = .(surfaceData.Ptr, linePitch, slicePitch);
index++;
surfaceDatas.Add(surfaceData);
}
}
Texture result = null;
switch (dimension)
{
case .Texture2D:
if (isCubemap)
{
Runtime.NotImplemented();
}
else
{
Texture2DDesc desc = .(width, height, pixelFormat, arraySize, mipMapCount, .Immutable, .None);
Texture2D texture = new Texture2D(desc);
texture.SetData(slices);
result = texture;
}
default:
Runtime.NotImplemented();
}
result.SamplerState = SamplerStateManager.GetSampler(sampler);
return result;
}
private Result<SamplerStateDescription> ReadSampler(Stream dataStream)
{
SamplerStateDescription sampler;
sampler.MinFilter = Try!(dataStream.Read<FilterFunction>());
sampler.MagFilter = Try!(dataStream.Read<FilterFunction>());
sampler.MipFilter = Try!(dataStream.Read<FilterFunction>());
sampler.FilterMode = Try!(dataStream.Read<FilterMode>());
sampler.ComparisonFunction = Try!(dataStream.Read<ComparisonFunction>());
sampler.AddressModeU = Try!(dataStream.Read<TextureAddressMode>());
sampler.AddressModeV = Try!(dataStream.Read<TextureAddressMode>());
sampler.AddressModeW = Try!(dataStream.Read<TextureAddressMode>());
sampler.MipLODBias = Try!(dataStream.Read<float>());
sampler.MipMinLOD = Try!(dataStream.Read<float>());
sampler.MipMaxLOD = Try!(dataStream.Read<float>());
sampler.MaxAnisotropy = Try!(dataStream.Read<uint8>());
sampler.BorderColor = Try!(dataStream.Read<ColorRGBA>());
return sampler;
}
}
+81 -136
View File
@@ -470,69 +470,72 @@ class EditorContentManager : IContentManager
return .Invalid;
}
CachedAsset cacheEntry = _assetCache.GetCacheEntry(handle);
if (cacheEntry != null)
{
// TODO: Load asset with new loaders
}
String filePath = scope String(resultNode->Value.Path);
AssetNode assetNode = resultNode->Value;
AssetFile file = assetNode.AssetFile;
GetResourceAndSubassetName(assetNode.Identifier, let resourceName, let subassetName);
IAssetLoader assetLoader = GetAssetLoader(file);
//Log.EngineLogger.AssertDebug(assetLoader != null);
if (assetLoader == null)
{
Log.EngineLogger.Error($"No asset loader registered for asset \"{resultNode->Value.Identifier}\" ({handle}).");
return .Invalid;
}
CachedAsset cacheEntry = _assetCache.GetCacheEntry(handle);
Asset loadedAsset;
// TODO: Support lazy loading for all asset types
if (!(assetLoader is EditorTextureAssetLoader) || blocking)
// TODO: Remove this check once we no longer need the old stuff
if (cacheEntry != null)
{
Stream stream = OpenStream(filePath, true);
loadedAsset = assetLoader.LoadAsset(stream, file.AssetConfig.Config, resourceName, subassetName, this);
delete stream;
if (loadedAsset == null)
return .Invalid;
// TODO: Load asset with new loaders
loadedAsset = LoadFromCache(handle, blocking);
}
else
{
PlaceholderAsset placeholder = new PlaceholderAsset(file, assetLoader, .Loading);
// else use the old mess...
String filePath2 = new String(filePath);
String newResourceName = new String(resourceName);
String newSesourceName = subassetName == null ? null : new String(subassetName.Value);
String filePath = scope String(resultNode->Value.Path);
placeholder.LoadingTask = new Task(new () => {
AsyncLoadAsset(placeholder, filePath2, assetLoader, file,
newResourceName, newSesourceName);
});
GetResourceAndSubassetName(assetNode.Identifier, let resourceName, let subassetName);
ThreadPool.QueueUserWorkItem(placeholder.LoadingTask);
IAssetLoader assetLoader = GetAssetLoader(file);
loadedAsset = placeholder;
//Log.EngineLogger.AssertDebug(assetLoader != null);
if (assetLoader == null)
{
Log.EngineLogger.Error($"No asset loader registered for asset \"{resultNode->Value.Identifier}\" ({handle}).");
return .Invalid;
}
// TODO: Support lazy loading for all asset types
if (!(assetLoader is EditorTextureAssetLoader) || blocking)
{
Stream stream = OpenStream(filePath, true);
loadedAsset = assetLoader.LoadAsset(stream, file.AssetConfig.Config, resourceName, subassetName, this);
delete stream;
if (loadedAsset == null)
return .Invalid;
}
else
{
PlaceholderAsset placeholder = new PlaceholderAsset(file, assetLoader, .Loading);
String filePath2 = new String(filePath);
String newResourceName = new String(resourceName);
String newSesourceName = subassetName == null ? null : new String(subassetName.Value);
placeholder.LoadingTask = new Task(new () => {
AsyncLoadAsset(placeholder, filePath2, assetLoader, file,
newResourceName, newSesourceName);
});
ThreadPool.QueueUserWorkItem(placeholder.LoadingTask);
loadedAsset = placeholder;
}
}
loadedAsset.Identifier = assetNode.Identifier;
_handleToAsset.Add(handle, loadedAsset);
loadedAsset.[Friend]_contentManager = this;
loadedAsset.[Friend]_handle = handle;
// Add to Identifier -> Handle map
_handleToAsset.Add(handle, loadedAsset);
_identiferToHandle.Add(loadedAsset.Identifier, handle);
file.[Friend]_loadedAsset = loadedAsset;
@@ -567,99 +570,6 @@ class EditorContentManager : IContentManager
return .Invalid;
}
//Result<TreeNode<AssetNode>> resultNode = AssetHierarchy.GetNodeFromIdentifier(fixedIdentifier);
//resultNode.
/*
if (_identiferToHandle.TryGetValue(fixedIdentifier, let asset))
return asset;
GetResourceAndSubassetName(fixedIdentifier, let resourceName, let subassetName);
Result<TreeNode<AssetNode>> resultNode = AssetHierarchy.GetNodeFromIdentifier(fixedIdentifier);
if (resultNode case .Err)
{
Log.EngineLogger.Error($"Could not find asset \"{fixedIdentifier}\".");
return .Invalid;
}
String filePath = scope String(resultNode->Value.Path);
AssetFile file = resultNode->Value.AssetFile;
IAssetLoader assetLoader = GetAssetLoader(file);
// TODO: what are we supposed to do if we don't find a loader? Surely not crash...
//Log.EngineLogger.AssertDebug(assetLoader != null);
if (assetLoader == null)
{
Log.EngineLogger.Error($"No asset loader registered for asset {identifier}.");
return .Invalid;
}
Asset loadedAsset;
// TODO: Support lazy loading for all asset types
if (!(assetLoader is EditorTextureAssetLoader) || blocking)
{
Stream stream = OpenStream(filePath, true);
loadedAsset = assetLoader.LoadAsset(stream, file.AssetConfig.Config, resourceName, subassetName, this);
delete stream;
if (loadedAsset == null)
return .Invalid;
}
else
{
PlaceholderAsset placeholder = new PlaceholderAsset(file, assetLoader, .Loading);
String filePath2 = new String(filePath);
String newResourceName = new String(resourceName);
String newSesourceName = subassetName == null ? null : new String(subassetName.Value);
placeholder.LoadingTask = new Task(new () => {
AsyncLoadAsset(placeholder, filePath2, assetLoader, file,
newResourceName, newSesourceName);
});
ThreadPool.QueueUserWorkItem(placeholder.LoadingTask);
loadedAsset = placeholder;
}
loadedAsset.Identifier = fixedIdentifier;
AssetHandle handle = .Invalid;
if (file.AssetConfig.AssetHandle == .Invalid)
{
handle = ManageAsset(loadedAsset);
// TODO: Does this ever happen?
file.AssetConfig.AssetHandle = handle;
}
else
{
handle = file.AssetConfig.AssetHandle;
_handleToAsset.Add(handle, loadedAsset);
loadedAsset.[Friend]_contentManager = this;
loadedAsset.[Friend]_handle = handle;
}
// ManageAsset increases RefCount, but this scope also holds a reference.
loadedAsset.ReleaseRef();
// Add to Identifier -> Handle map
_identiferToHandle.Add(loadedAsset.Identifier, handle);
file.[Friend]_loadedAsset = loadedAsset;
return handle;*/
}
private void AsyncLoadAsset(PlaceholderAsset placeholder, String filePath, IAssetLoader assetLoader, AssetFile file, String resourceName, String subassetName)
@@ -998,4 +908,39 @@ class EditorContentManager : IContentManager
//UnmanageAsset(asset);
//ManageAsset(asset);
}
// TODO: obviously use a map or something...
TextureLoader textureLoader = new .();
private IProcessedAssetLoader GetLoader(AssetType assetType)
{
switch (assetType)
{
case .Texture:
return textureLoader;
default:
return null;
}
}
private Asset LoadFromCache(AssetHandle handle, bool isBlocking)
{
FileStream file = scope .();
CachedAsset asset = _assetCache.GetCacheEntry(handle);
// TODO: Actually return a placeholder, but they probably need rework too...
if (_assetCache.OpenFileStream(asset, file) case .Err)
return null;
IProcessedAssetLoader loader = GetLoader(asset.AssetType);
switch (loader.Load(file))
{
case .Ok(let loadedAsset):
return loadedAsset;
case .Err:
return null;
}
}
}