Start of async asset loading

- Refactored content manager and asset loaders
- Asset placeholder
- Error asset
This commit is contained in:
Simon Lübeß
2023-03-18 18:59:30 +01:00
parent 7b6662cbc4
commit 50714976e9
11 changed files with 329 additions and 321 deletions
+5 -8
View File
@@ -8,7 +8,7 @@ using System.IO;
namespace GlitchyEngine.Content;
[BonTarget]
class Asset : RefCounter
abstract class Asset : RefCounter
{
internal AssetHandle _handle = .Invalid;
@@ -22,15 +22,12 @@ class Asset : RefCounter
public StringView Identifier
{
get => _identifier;
set
{
_contentManager?.UpdateAssetIdentifier(this, _identifier, value);
_identifier.Set(value);
// TODO: do we need to tell the content manager, that the name changed?
}
internal set => _identifier.Set(value);
}
/// If true the asset is completely loaded. If false it is only partially loaded (if at all).
public bool Complete { get; internal set; }
// TODO: do we need unmanaged assets? Probably not...
/// Gets the content manager that manages this asset; or null if this asset isn't managed.
public IContentManager ContentManager => _contentManager;
+5 -5
View File
@@ -11,10 +11,10 @@ struct AssetHandle : IHashable
private UUID _uuid;
/// Defines an asset that is invalid.
public const AssetHandle Invalid = .(UUID(0xAAAA'AAAA'AAAA'AAAA));
public const AssetHandle Invalid = .(UUID(0));
public bool IsValid => this == .Invalid;
public bool IsInvalid => !IsValid;
public bool IsValid => this != .Invalid;
public bool IsInvalid => this == .Invalid;
/// Create a new random AssetHandle
public this()
@@ -49,8 +49,8 @@ struct AssetHandle<T> where T : Asset
public const Self Invalid = .();
public bool IsValid => this == .Invalid;
public bool IsInvalid => !IsValid;
public bool IsValid => this != .Invalid;
public bool IsInvalid => this == .Invalid;
public this(AssetHandle handle, IContentManager contentManager = null)
{
+10 -13
View File
@@ -57,19 +57,25 @@ namespace GlitchyEngine.Content
/// @param contentManager The content manager used to load the asset.
/// @returns The loaded asset.
Asset LoadAsset(Stream file, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager);
/// Returns the placeholder asset.
Asset GetPlaceholderAsset(Type assetType);
/// Returns the error asset.
Asset GetErrorAsset(Type assetType);
}
static class Content
{
/// Loads the specified asset with the given contentManager or the current applications content manager.
public static AssetHandle LoadAsset(StringView assetIdentifier, IContentManager contentManager = null)
public static AssetHandle LoadAsset(StringView assetIdentifier, IContentManager contentManager = null, bool blocking = false)
{
var contentManager;
if (contentManager == null)
contentManager = Application.Get().ContentManager;
AssetHandle handle = contentManager.LoadAsset(assetIdentifier);
AssetHandle handle = contentManager.LoadAsset(assetIdentifier, blocking);
return handle;
}
@@ -111,7 +117,7 @@ namespace GlitchyEngine.Content
interface IContentManager
{
/// Loads the Asset with the given handle and returns the handle.
AssetHandle LoadAsset(StringView assetIdentifier);
AssetHandle LoadAsset(StringView assetIdentifier, bool blocking = false);
/// Returns the asset for the given handle or null, if it isn't loaded.
Asset GetAsset(AssetHandle handle)
@@ -128,10 +134,6 @@ namespace GlitchyEngine.Content
/// The content manager will no longer manage the asset.
void UnmanageAsset(AssetHandle asset);
// TODO: Maybe calling UnmanageAsset -> ManageAsset is enough....
/// Provides a method for the asset to tell its content manager that the identifer changed.
void UpdateAssetIdentifier(Asset asset, StringView oldIdentifier, StringView newIdentifier);
/// Returns a data stream for the given asset.
Stream GetStream(StringView assetIdentifier);
@@ -149,7 +151,7 @@ namespace GlitchyEngine.Content
Runtime.NotImplemented();
}
public AssetHandle LoadAsset(StringView assetIdentifier)
public AssetHandle LoadAsset(StringView assetIdentifier, bool blocking = false)
{
Runtime.NotImplemented();
}
@@ -169,11 +171,6 @@ namespace GlitchyEngine.Content
Runtime.NotImplemented();
}
public void UpdateAssetIdentifier(Asset asset, StringView oldIdentifier, StringView newIdentifier)
{
Runtime.NotImplemented();
}
public Stream GetStream(StringView assetIdentifier)
{
Runtime.NotImplemented();
@@ -101,7 +101,7 @@ namespace GlitchyEngine.Renderer
LoadDdsResourcePlatform(stream, ref nativeTexture);
let resType = nativeTexture.GetResourceType();
Log.EngineLogger.Assert(resType == .Texture2D, scope $"The texture \"{_path}\" is not a 2D texture (it is {resType}).");
Log.EngineLogger.Assert(resType == .Texture2D, scope $"The texture is not a 2D texture (it is {resType}).");
nativeTexture.GetDescription(out nativeDesc);
}
@@ -261,13 +261,6 @@ namespace GlitchyEngine.Renderer
{
return .(_nativeResourceView, _samplerState?.nativeSamplerState);
}
protected override void PlatformSneakySwappyTexture(Texture2D otherTexture)
{
Swap!(nativeDesc, otherTexture.nativeDesc);
Swap!(nativeTexture, otherTexture.nativeTexture);
Swap!(_nativeResourceView, otherTexture._nativeResourceView);
}
}
extension TextureCube
-74
View File
@@ -63,19 +63,11 @@ namespace GlitchyEngine.Renderer
public class Texture2D : Texture
{
protected String _path ~ delete _;
//public override extern uint32 Width {get;}
//public override extern uint32 Height {get;}
public override uint32 Depth => 1;
//public override extern uint32 ArraySize {get;}
//public override extern uint32 MipLevels {get;}
private this(StringView path, bool pngSrgb = false)
{
_path = new String(path);
LoadTexture(pngSrgb);
}
// TODO: remove
private this(Stream data)
@@ -83,72 +75,6 @@ namespace GlitchyEngine.Renderer
LoadDds(data);
}
const String PngMagicWord = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
const String DdsMagicWord = "DDS ";
private void LoadTexture(bool pngSrgb)
{
Debug.Profiler.ProfileResourceFunction!();
Stream data = Application.Get().ContentManager.GetStream(_path);
defer delete data;
var readResult = data.Read<char8[8]>();
data.Position = 0;
char8[8] magicWord;
if (readResult case .Ok(out magicWord))
{
StringView strView = .(&magicWord, magicWord.Count);
if (strView.StartsWith(PngMagicWord))
{
LoadPng(data, pngSrgb);
}
else if (strView.StartsWith(DdsMagicWord))
{
LoadDds(data);
}
else
{
Runtime.FatalError("Unknown image format.");
}
}
}
protected void LoadPng(Stream stream, bool srgb)
{
Debug.Profiler.ProfileResourceFunction!();
uint8[] pngData = new:ScopedAlloc! uint8[stream.Length];
var result = stream.TryRead(pngData);
if (result case .Err(let err))
{
Log.EngineLogger.Error($"Failed to read data from stream. Texture: \"{_path}\", Error: {err}");
}
uint8* rawData = ?;
uint32 width = 0, height = 0;
uint32 errorCode = LodePng.LodePng.Decode32(&rawData, &width, &height, pngData.Ptr, (.)pngData.Count);
Debug.Assert(errorCode == 0, "Failed to load png File");
// TODO: load as SRGB because PNGs are usually not stored as linear
//Texture2DDesc desc = .(width, height, .R8G8B8A8_UNorm_SRGB, 1, 1, .Immutable);
Texture2DDesc desc = .(width, height, srgb? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm, 1, 1, .Immutable);
PrepareTexturePlatform(desc, false);
SetData<Color>((.)rawData);
LodePng.LodePng.Free(rawData);
}
protected void LoadDds(Stream stream)
{
LoadDdsPlatform(stream);