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; 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); 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.Content;
using GlitchyEngine; using GlitchyEngine;
using GlitchyEngine.Renderer; using GlitchyEngine.Renderer;
using GlitchyEngine.Math;
using static GlitchyEditor.Assets.Importers.LoadedTextureInfo; using static GlitchyEditor.Assets.Importers.LoadedTextureInfo;
namespace GlitchyEditor.Assets.Importers; namespace GlitchyEditor.Assets.Importers;
@@ -234,11 +235,20 @@ class TextureProcessorConfig : AssetProcessorConfig
[BonInclude] [BonInclude]
private GenerateMipMaps _generateMipMaps; private GenerateMipMaps _generateMipMaps;
[BonInclude]
private SamplerStateDescription _samplerStateDescription = .();
public GenerateMipMaps GenerateMipMaps public GenerateMipMaps GenerateMipMaps
{ {
get => _generateMipMaps; get => _generateMipMaps;
set => SetIfChanged(ref _generateMipMaps, value); set => SetIfChanged(ref _generateMipMaps, value);
} }
public SamplerStateDescription SamplerStateDescription
{
get => _samplerStateDescription;
set => SetIfChanged(ref _samplerStateDescription, value);
}
} }
abstract class ProcessedResource abstract class ProcessedResource
@@ -267,6 +277,8 @@ class ProcessedTexture : ProcessedResource
public int Height = -1; public int Height = -1;
public int Depth = -1; public int Depth = -1;
public SamplerStateDescription SamplerStateDescription;
public override AssetType AssetType => .Texture; public override AssetType AssetType => .Texture;
public class TextureSurface public class TextureSurface
@@ -277,9 +289,11 @@ class ProcessedTexture : ProcessedResource
public int Depth; public int Depth;
public int MipLevel; public int MipLevel;
public int ArraySlice; public int ArraySlice;
public int LinePitch;
public int SlicePitch;
[AllowAppend] [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]; uint8[] pixelData = append uint8[data.Length];
data.CopyTo(pixelData); data.CopyTo(pixelData);
@@ -290,6 +304,8 @@ class ProcessedTexture : ProcessedResource
Depth = depth; Depth = depth;
MipLevel = mipLevel; MipLevel = mipLevel;
ArraySlice = arraySlice; ArraySlice = arraySlice;
LinePitch = linePitch;
SlicePitch = slicePitch;
} }
public uint64 LoadRaw(int x, int y, int z, Format format, ComponentInfo component) 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.Height = importedTexture.TextureInfo.Height;
processedTexture.Depth = importedTexture.TextureInfo.Depth; processedTexture.Depth = importedTexture.TextureInfo.Depth;
processedTexture.SamplerStateDescription = config.SamplerStateDescription;
processedTexture.SetSurfaceCount(importedTexture.TextureInfo.ArraySize, importedTexture.TextureInfo.MipMapCount); processedTexture.SetSurfaceCount(importedTexture.TextureInfo.ArraySize, importedTexture.TextureInfo.MipMapCount);
for (LoadedSurface loadedSurface in importedTexture.Surfaces) for (LoadedSurface loadedSurface in importedTexture.Surfaces)
{ {
ProcessedTexture.TextureSurface surface = new .(loadedSurface.Width, loadedSurface.Height, loadedSurface.Depth, 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; processedTexture.Surfaces[loadedSurface.ArrayIndex, loadedSurface.MipLevel] = surface;
} }
@@ -499,7 +517,9 @@ class TextureProcessor : IAssetProcessor
if (smallerLevel == null) 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? // TODO: Kaiser mip maps?
@@ -556,6 +576,8 @@ class TextureExporter : IAssetExporter
Depth of larges mip-slice (4 bytes) Depth of larges mip-slice (4 bytes)
Array size (4 bytes) Array size (4 bytes)
Mip map levels (4 bytes) Mip map levels (4 bytes)
Is Cubemap (1 byte)
Data Byte count (8 bytes)
Pixeldata Pixeldata
{ {
Array[0]: Mip[0] Mip[1] ... Mip[M] 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.Depth));
Try!(stream.Write((uint32)processedTexture.ArraySize)); Try!(stream.Write((uint32)processedTexture.ArraySize));
Try!(stream.Write((uint32)processedTexture.MipMapCount)); Try!(stream.Write((uint32)processedTexture.MipMapCount));
Try!(stream.Write(processedTexture.IsCubeMap));
Try!(WriteSamplerStateDescription(stream, processedTexture.SamplerStateDescription));
for (int arraySlice < processedTexture.ArraySize) for (int arraySlice < processedTexture.ArraySize)
{ {
@@ -600,28 +625,121 @@ class TextureExporter : IAssetExporter
if (validateDepth < 1) if (validateDepth < 1)
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)); Try!(stream.TryWrite(slice.PixelData));
} }
} }
return .Ok; return .Ok;
} }
}
class TextureLoader private Result<void> WriteSamplerStateDescription(Stream stream, SamplerStateDescription sampler)
{ {
public Result<Asset> Load(Stream data, AssetIdentifier assetIdentifier) 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
{ {
Dimension dimension = Try!(data.Read<Dimension>()); public Result<Asset> Load(Stream dataStream)
Format pixelFormat = Try!(data.Read<Format>()); {
uint32 width = Try!(data.Read<uint32>()); Dimension dimension = Try!(dataStream.Read<Dimension>());
uint32 height = Try!(data.Read<uint32>()); Format pixelFormat = Try!(dataStream.Read<Format>());
uint32 depth = Try!(data.Read<uint32>()); uint32 width = Try!(dataStream.Read<uint32>());
uint32 arraySize = Try!(data.Read<uint32>()); uint32 height = Try!(dataStream.Read<uint32>());
uint32 mipMapCount = Try!(data.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>());
SamplerStateDescription sampler = Try!(ReadSampler(dataStream));
List<uint8[]> surfaceDatas = scope .(mipMapCount * arraySize);
defer { ClearAndDeleteItems!(surfaceDatas); }
return .Ok(null); 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;
} }
} }
+47 -102
View File
@@ -470,18 +470,25 @@ class EditorContentManager : IContentManager
return .Invalid; return .Invalid;
} }
AssetNode assetNode = resultNode->Value;
AssetFile file = assetNode.AssetFile;
CachedAsset cacheEntry = _assetCache.GetCacheEntry(handle); CachedAsset cacheEntry = _assetCache.GetCacheEntry(handle);
Asset loadedAsset;
// TODO: Remove this check once we no longer need the old stuff
if (cacheEntry != null) if (cacheEntry != null)
{ {
// TODO: Load asset with new loaders // TODO: Load asset with new loaders
loadedAsset = LoadFromCache(handle, blocking);
} }
else
{
// else use the old mess...
String filePath = scope String(resultNode->Value.Path); String filePath = scope String(resultNode->Value.Path);
AssetNode assetNode = resultNode->Value;
AssetFile file = assetNode.AssetFile;
GetResourceAndSubassetName(assetNode.Identifier, let resourceName, let subassetName); GetResourceAndSubassetName(assetNode.Identifier, let resourceName, let subassetName);
IAssetLoader assetLoader = GetAssetLoader(file); IAssetLoader assetLoader = GetAssetLoader(file);
@@ -493,8 +500,6 @@ class EditorContentManager : IContentManager
return .Invalid; return .Invalid;
} }
Asset loadedAsset;
// TODO: Support lazy loading for all asset types // TODO: Support lazy loading for all asset types
if (!(assetLoader is EditorTextureAssetLoader) || blocking) if (!(assetLoader is EditorTextureAssetLoader) || blocking)
{ {
@@ -524,15 +529,13 @@ class EditorContentManager : IContentManager
loadedAsset = placeholder; loadedAsset = placeholder;
} }
}
loadedAsset.Identifier = assetNode.Identifier; loadedAsset.Identifier = assetNode.Identifier;
_handleToAsset.Add(handle, loadedAsset);
loadedAsset.[Friend]_contentManager = this; loadedAsset.[Friend]_contentManager = this;
loadedAsset.[Friend]_handle = handle; loadedAsset.[Friend]_handle = handle;
// Add to Identifier -> Handle map _handleToAsset.Add(handle, loadedAsset);
_identiferToHandle.Add(loadedAsset.Identifier, handle); _identiferToHandle.Add(loadedAsset.Identifier, handle);
file.[Friend]_loadedAsset = loadedAsset; file.[Friend]_loadedAsset = loadedAsset;
@@ -567,99 +570,6 @@ class EditorContentManager : IContentManager
return .Invalid; 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) private void AsyncLoadAsset(PlaceholderAsset placeholder, String filePath, IAssetLoader assetLoader, AssetFile file, String resourceName, String subassetName)
@@ -998,4 +908,39 @@ class EditorContentManager : IContentManager
//UnmanageAsset(asset); //UnmanageAsset(asset);
//ManageAsset(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;
}
}
} }