Skip to content

Commit

Permalink
Add more asset implementation stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
Golle committed Aug 31, 2022
1 parent 8c2a753 commit 15181c0
Show file tree
Hide file tree
Showing 19 changed files with 369 additions and 100 deletions.
17 changes: 4 additions & 13 deletions src/Titan.Assets/NewAssets/Asset.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
using Titan.Core;
using Titan.Core.Threading2;

namespace Titan.Assets.NewAssets;

public struct Asset
{
public AssetState State;

public Handle<JobApi> JobHandle;
public Handle AssetHandle;
public int ReferenceCount;

public AssetDescriptor Descriptor;
}
/// <summary>
/// Struct used for the asset handle Handle<Asset>
/// </summary>
public struct Asset{}
26 changes: 26 additions & 0 deletions src/Titan.Assets/NewAssets/AssetContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Titan.Core;
using Titan.Core.Threading2;
using Titan.FileSystem;

namespace Titan.Assets.NewAssets;

/// <summary>
/// Struct that contains all information needed for assets.
/// NOTE(Jens): this will consume a bit of memory depending on the amount of assets in the game. Might be fine, but good to keep an eye on.
/// </summary>
internal unsafe struct AssetContext
{

public AssetState State;
public Handle<JobApi> JobHandle;
public Handle AssetHandle;
public volatile int ReferenceCount;

//File loading
public void* FileBuffer;
public FileSystemApi* FileSystemApi;
public FileHandle FileHandle;


public AssetDescriptor Descriptor;
}
15 changes: 13 additions & 2 deletions src/Titan.Assets/NewAssets/AssetFile.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using Titan.Core.Logging;
using Titan.FileSystem;

Expand All @@ -8,6 +9,8 @@ public unsafe struct AssetFile
{
private FileHandle _handle;
private FileSystemApi* _fileSystem;
private long _length;

public static bool Open(ReadOnlySpan<char> path, FileSystemApi* fileSystem, out AssetFile file)
{
file = default;
Expand All @@ -17,10 +20,12 @@ public static bool Open(ReadOnlySpan<char> path, FileSystemApi* fileSystem, out
Logger.Error<AssetFile>($"Failed to open file at path {path}.");
return false;
}
var length = fileSystem->GetLength(handle);
file = new AssetFile
{
_handle = handle,
_fileSystem = fileSystem
_fileSystem = fileSystem,
_length = length
};
return true;
}
Expand All @@ -33,5 +38,11 @@ public void Close()
}
}

public long GetLength() => _fileSystem->GeLength(_handle);
public int Read(Span<byte> buffer, ulong offset)
{
Debug.Assert(_handle.IsValid);
return _fileSystem->Read(_handle, buffer, offset);
}

public long GetLength() => _length;
}
93 changes: 93 additions & 0 deletions src/Titan.Assets/NewAssets/AssetFileAccessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using System;
using System.Diagnostics;
using Titan.Core.Logging;
using Titan.FileSystem;
using Titan.Memory;

namespace Titan.Assets.NewAssets;

internal unsafe struct AssetFileAccessor
{
private ManifestToFile* _files;
private int _count;

private PlatformAllocator* _allocator;
public static bool Create(PlatformAllocator* allocator, FileSystemApi* fileSystem, AssetsConfiguration[] configs, out AssetFileAccessor accessor)
{
accessor = default;
var files = allocator->Allocate<ManifestToFile>(configs.Length);
if (files == null)
{
Logger.Error<AssetFileAccessor>($"Failed to allocate a block for {nameof(ManifestToFile)} with size {sizeof(ManifestToFile) * configs.Length} bytes");
return false;
}

for (var i = 0; i < configs.Length; ++i)
{
ref var fileRef = ref files[i];
fileRef.Id = configs[i].Id;
if (!AssetFile.Open(configs[i].TitanPakFile, fileSystem, out fileRef.File))
{
Logger.Error<AssetFileAccessor>($"Failed to open file {configs[i].TitanPakFile}");
goto Error;
}
Logger.Trace<AssetFileAccessor>($"Opened file {configs[i].TitanPakFile} with size {files[i].File.GetLength()} bytes");
}
accessor = new AssetFileAccessor
{
_allocator = allocator,
_files = files,
_count = configs.Length
};
return true;
Error:

//NOTE(Jens): if there's an error, close all open file handles.
for (var i = 0; i < configs.Length; ++i)
{
files[i].File.Close();
}
return false;
}


public int Read(Span<byte> buffer, in AssetDescriptor descriptor)
{
Debug.Assert(buffer.Length >= (int)descriptor.Reference.Size, $"Buffer size is {buffer.Length} bytes, minimum required is {descriptor.Reference.Size} bytes.");

var file = GetFileForManifest(descriptor.ManifestId);
Debug.Assert(file != null, $"TitanPak file with ID {descriptor.ManifestId} was not found.");

return file->Read(buffer[..(int)descriptor.Reference.Size], descriptor.Reference.Offset);
}

private AssetFile* GetFileForManifest(uint manifestId)
{
for (var i = 0; i < _count; ++i)
{
if (_files[i].Id == manifestId)
{
return &_files[i].File;
}
}
return null;
}


public void Release()
{
for (var i = 0; i < _count; ++i)
{
_files[i].File.Close();
}
_allocator->Free(_files);
_files = null;
_count = 0;
}

private struct ManifestToFile
{
public uint Id;
public AssetFile File;
}
}
9 changes: 9 additions & 0 deletions src/Titan.Assets/NewAssets/AssetManager.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Titan.Core;
Expand Down Expand Up @@ -51,4 +52,12 @@ public Handle<T> GetAssetHandle<T>(in Handle<Asset> assetHandle) where T : unman
Debug.Assert(asset.State == AssetState.Loaded, $"Trying to access an asset that is not loaded. Use {nameof(IsLoaded)}(Handle) to check is an asset is available.");
return asset.AssetHandle;
}

public Handle<T> GetAssetHandleFromDescriptor<T>(in AssetDescriptor descriptor) where T : unmanaged
{
//NOTE(Jens): This is a synchronous call to support getting the handle to an asset that has already been loaded.
//NOTE(Jens): Need to figure out how to handle reference counting in this case
//NOTE(Jens): what happens if the asset has not been loaded? just return Invalid?
throw new NotImplementedException("Implement this to support reading the handle of already loaded asset.");
}
}
52 changes: 43 additions & 9 deletions src/Titan.Assets/NewAssets/AssetModule.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using System;
using System.IO;
using System.Linq;
using Titan.Core.Logging;
using Titan.ECS.App;
using Titan.ECS.Scheduler;
using Titan.ECS.Systems;
using Titan.FileSystem;
using Titan.Memory;

Expand All @@ -20,11 +23,14 @@ public unsafe struct AssetsModule : IModule
{
public static void Build(AppBuilder builder)
{

var s = sizeof(AssetContext);
var b = s * 1000;
var allocator = builder.GetResourcePointer<PlatformAllocator>();
var fileApi = builder.GetResourcePointer<FileSystemApi>();
var assetConfigs = builder
.GetConfigurations<AssetsConfiguration>()
.ToArray();
;


//set up paths where the assets will be loaded from
Expand All @@ -33,29 +39,57 @@ public static void Build(AppBuilder builder)
var devSettings = builder.GetConfiguration<AssetsDevConfiguration>();
if (devSettings != null)
{


assetConfigs = assetConfigs.Select(c => c with
{
ManifestFile = Path.Combine(devSettings.AssetsFolder, c.ManifestFile),
TitanPakFile = Path.Combine(devSettings.TitanPakFolder, c.TitanPakFile)
});
}

//
#else

#endif
if (!AssetRegistry.Create(allocator, assetConfigs, out var registry))
var configs = assetConfigs.ToArray();
if (!AssetRegistry.Create(allocator, configs, out var registry))
{
Logger.Error<AssetsModule>("Failed to initialize the asset registry");
return;
}

if (AssetFile.Open(@"F:\Git\Titan\samples\Titan.Sandbox\assets\bin\data001.titanpak", fileApi, out var file))
if (!AssetFileAccessor.Create(allocator, fileApi, configs, out var accessor))
{
Logger.Trace<AssetsModule>($"File opened! Size: {file.GetLength()}.");
Logger.Error<AssetsModule>($"Failed to initialize the {nameof(AssetFileAccessor)}");
return;
}

file.Close();

builder
.AddResource(registry)
.AddSystemToStage<AssetSystem>(Stage.PreUpdate);
.AddResource(accessor)
.AddSystemToStage<AssetSystem>(Stage.PreUpdate)
.AddShutdownSystem<AssetModuleTearDown>(RunCriteria.Always);
}



private struct AssetModuleTearDown : IStructSystem<AssetModuleTearDown>
{
private AssetRegistry* Registry;
private AssetFileAccessor* Accessor;

public static void Init(ref AssetModuleTearDown system, in SystemsInitializer init)
{
system.Registry = init.GetResourcePointer<AssetRegistry>();
system.Accessor = init.GetResourcePointer<AssetFileAccessor>();
}

public static void Update(ref AssetModuleTearDown system)
{
system.Registry->Release();
system.Accessor->Release();
}

public static bool ShouldRun(in AssetModuleTearDown system)
=> throw new InvalidOperationException($"The {nameof(AssetModuleTearDown)} should be marked as {RunCriteria.Once}");
}
}
15 changes: 9 additions & 6 deletions src/Titan.Assets/NewAssets/AssetRegistry.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
Expand All @@ -14,7 +15,7 @@ internal unsafe struct AssetRegistry : IResource
//NOTE(Jens): the handle offset is to allow 0 indexed arrays. Handle<T>.IsInvalid is checking for 0. We could also leave index 0 and have a 1 indexed array. That would remove the addition/subtraction needed to access the assets.
private const int HandleOffset = 70000;
private int* _manifestOffsets;
private Asset* _assets;
private AssetContext* _assets;
private int _size;
private uint _highestManifestId;

Expand All @@ -28,22 +29,22 @@ public static bool Create(PlatformAllocator* allocator, AssetsConfiguration[] co

//NOTE(Jens): Size of all assets + the maninfest offsets
var manifestIndexSize = highestManifestId * sizeof(int);
var totalSize = sizeof(Asset) * assetCount + manifestIndexSize;
var totalSize = sizeof(AssetContext) * assetCount + manifestIndexSize;

var mem = (byte*)allocator->Allocate((nuint)totalSize, initialize: true);
Debug.Assert(mem != null, $"Failed to allocate {totalSize} bytes of memory.");
var manifestOffsets = (int*)mem;
var assets = (Asset*)(mem + manifestIndexSize);
var assets = (AssetContext*)(mem + manifestIndexSize);
var offset = 0;

//NOTE(Jens): Set offsets to -1. This is to detect request with descriptors that have not been registered at startup.
MemoryUtils.Init(manifestOffsets, manifestIndexSize, byte.MaxValue);
foreach (var config in configs)
{
manifestOffsets[config.Id] = offset;
for (var i = 0; i < config.AssetDescriptors.Length; ++i)
{
assets[i + offset] = new Asset
assets[i + offset] = new AssetContext
{
AssetHandle = Handle.Null,
Descriptor = config.AssetDescriptors[i],
Expand Down Expand Up @@ -82,7 +83,9 @@ public void Release()
//NOTE(Jens): not sure if we want to free the memory or not.
}

public ref Asset Get(in Handle<Asset> handle)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<AssetContext> GetAssets() => new(_assets, _size);
public ref AssetContext Get(in Handle<Asset> handle)
{
var index = handle - HandleOffset;
Debug.Assert(index >= 0 && index < _size, "Out of bounds");
Expand Down
4 changes: 3 additions & 1 deletion src/Titan.Assets/NewAssets/AssetState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ public enum AssetState
Unloaded,
LoadRequested,
ReadingFile,
ReadFileCompleted,
Loading,
Loaded,
/*
* Add states for resolving dependencies
*/
UnloadRequested
UnloadRequested,
Unloading
}
Loading

0 comments on commit 15181c0

Please sign in to comment.