Various conversion to memory arena and misc clean up

This commit is contained in:
2026-08-16 22:10:51 -04:00
parent d1b7c5dbbe
commit 262d91dd49
11 changed files with 53 additions and 69 deletions
+5 -5
View File
@@ -47,10 +47,11 @@ namespace Juliet
bool (*Close)(NonNullPtr<IOStreamDataPayload> data); bool (*Close)(NonNullPtr<IOStreamDataPayload> data);
}; };
extern JULIET_API IOStream* IOFromFile(String filename, String mode); extern JULIET_API IOStream* IOFromFile(NonNullPtr<Arena> arena, String filename, String mode);
// Let you use an interface to open any io. Is used internally by IOFromFile // Let you use an interface to open any io. Is used internally by IOFromFile
extern JULIET_API IOStream* IOFromInterface(NonNullPtr<const IOStreamInterface> streamInterface, NonNullPtr<IOStreamDataPayload> payload); extern JULIET_API IOStream* IOFromInterface(NonNullPtr<Arena> arena, NonNullPtr<const IOStreamInterface> streamInterface,
NonNullPtr<IOStreamDataPayload> payload);
// Write formatted string into the stream. // Write formatted string into the stream.
extern JULIET_API size_t IOPrintf(NonNullPtr<IOStream> stream, _Printf_format_string_ const char* format, ...); extern JULIET_API size_t IOPrintf(NonNullPtr<IOStream> stream, _Printf_format_string_ const char* format, ...);
@@ -61,9 +62,8 @@ namespace Juliet
extern JULIET_API int64 IOSize(NonNullPtr<IOStream> stream); extern JULIET_API int64 IOSize(NonNullPtr<IOStream> stream);
// TODO : Use memory arena because that Allocates extern JULIET_API ByteBuffer LoadFile(NonNullPtr<Arena> arena, String filename);
extern JULIET_API ByteBuffer LoadFile(String filename); extern JULIET_API ByteBuffer LoadFile(NonNullPtr<Arena> arena, NonNullPtr<IOStream> stream, bool closeStreamWhenDone);
extern JULIET_API ByteBuffer LoadFile(NonNullPtr<IOStream> stream, bool closeStreamWhenDone);
extern JULIET_API bool IOClose(NonNullPtr<IOStream> stream); extern JULIET_API bool IOClose(NonNullPtr<IOStream> stream);
} // namespace Juliet } // namespace Juliet
+2 -3
View File
@@ -9,8 +9,6 @@ namespace Juliet
struct HotReloadCode struct HotReloadCode
{ {
Arena* Arena;
String DLLFullPath; String DLLFullPath;
String LockFullPath; String LockFullPath;
String TransientDLLName; String TransientDLLName;
@@ -28,7 +26,8 @@ namespace Juliet
bool IsValid : 1; bool IsValid : 1;
}; };
extern JULIET_API void InitHotReloadCode(HotReloadCode& code, String dllName, String transientDllName, String lockFilename); extern JULIET_API void InitHotReloadCode(NonNullPtr<Arena> arena, HotReloadCode& code, String dllName,
String transientDllName, String lockFilename);
extern JULIET_API void ShutdownHotReloadCode(HotReloadCode& code); extern JULIET_API void ShutdownHotReloadCode(HotReloadCode& code);
extern JULIET_API void LoadCode(HotReloadCode& code); extern JULIET_API void LoadCode(HotReloadCode& code);
+17 -22
View File
@@ -1,15 +1,14 @@
#include <Core/HAL/IO/IOStream.h> #include <Core/HAL/IO/IOStream.h>
#include <Core/Common/String.h> #include <Core/Common/String.h>
#include <Core/HAL/IO/IOStream_Private.h> #include <Core/HAL/IO/IOStream_cpp.h>
#include <Core/Logging/LogManager.h> #include <Core/Logging/LogManager.h>
#include <Core/Logging/LogTypes.h> #include <Core/Logging/LogTypes.h>
#include <Core/Memory/Allocator.h>
#include <Core/Thread/Thread.h> #include <Core/Thread/Thread.h>
namespace Juliet namespace Juliet
{ {
IOStream* IOFromFile(String filename, String mode) IOStream* IOFromFile(NonNullPtr<Arena> arena, String filename, String mode)
{ {
if (!IsValid(filename)) if (!IsValid(filename))
{ {
@@ -22,14 +21,14 @@ namespace Juliet
return nullptr; return nullptr;
} }
return Internal::IOFromFile(filename, mode); return Internal::IOFromFile(arena, filename, mode);
} }
IOStream* IOFromInterface(NonNullPtr<const IOStreamInterface> streamInterface, NonNullPtr<IOStreamDataPayload> payload) IOStream* IOFromInterface(NonNullPtr<Arena> arena, NonNullPtr<const IOStreamInterface> streamInterface,
NonNullPtr<IOStreamDataPayload> payload)
{ {
Assert(streamInterface->Version >= sizeof(*streamInterface.Get())); Assert(streamInterface->Version >= sizeof(*streamInterface.Get()));
auto stream = ArenaPushStruct<IOStream>(arena);
auto stream = static_cast<IOStream*>(Calloc(1, sizeof(IOStream)));
if (stream) if (stream)
{ {
IOStreamInterface* dstInterface = &stream->Interface; IOStreamInterface* dstInterface = &stream->Interface;
@@ -132,23 +131,19 @@ namespace Juliet
return stream->Interface.Size(stream->Data); return stream->Interface.Size(stream->Data);
} }
ByteBuffer LoadFile(String filename) ByteBuffer LoadFile(NonNullPtr<Arena> arena, String filename)
{ {
IOStream* stream = IOFromFile(filename, WrapString("rb")); IOStream* stream = IOFromFile(arena, filename, WrapString("rb"));
if (!stream) if (!stream)
{ {
return {}; return {};
} }
return LoadFile(stream, true); return LoadFile(arena, stream, true);
} }
ByteBuffer LoadFile(NonNullPtr<IOStream> stream, bool closeStreamWhenDone) ByteBuffer LoadFile(NonNullPtr<Arena> arena, NonNullPtr<IOStream> stream, bool closeStreamWhenDone)
{ {
constexpr size_t kFileChunkSize = 1024; constexpr size_t kFileChunkSize = 1024;
uint8* data = nullptr;
uint8* newData = nullptr;
size_t totalSize = 0;
ByteBuffer resultBuffer = {};
auto deferred = Defer( auto deferred = Defer(
[&]() [&]()
@@ -168,12 +163,13 @@ namespace Juliet
loadChunks = true; loadChunks = true;
} }
size_t size = static_cast<size_t>(ssize); size_t size = static_cast<size_t>(ssize);
data = static_cast<uint8*>(Malloc(static_cast<size_t>(size + 1))); uint8* data = ArenaPushArray<uint8, false>(arena, size + 1);
if (!data) if (!data)
{ {
return {}; return {};
} }
size_t totalSize = 0;
while (true) while (true)
{ {
if (loadChunks) if (loadChunks)
@@ -181,13 +177,13 @@ namespace Juliet
if ((totalSize + kFileChunkSize) > size) if ((totalSize + kFileChunkSize) > size)
{ {
size = totalSize + kFileChunkSize; size = totalSize + kFileChunkSize;
newData = static_cast<uint8*>(Realloc(data, static_cast<size_t>(size + 1)));
if (!newData) // Not enough space, add some
uint8* newSpace = ArenaPushArray<uint8, false>(arena, kFileChunkSize);
if (!newSpace)
{ {
Free(data);
return {}; return {};
} }
data = newData;
} }
} }
@@ -211,9 +207,9 @@ namespace Juliet
// Adding null terminator // Adding null terminator
data[totalSize] = '\0'; data[totalSize] = '\0';
ByteBuffer resultBuffer = {};
resultBuffer.Data = reinterpret_cast<Byte*>(data); resultBuffer.Data = reinterpret_cast<Byte*>(data);
resultBuffer.Size = totalSize; resultBuffer.Size = totalSize;
return resultBuffer; return resultBuffer;
} }
@@ -224,7 +220,6 @@ namespace Juliet
{ {
result = stream->Interface.Close(stream->Data); result = stream->Interface.Close(stream->Data);
} }
Free(stream.Get());
return result; return result;
} }
@@ -15,5 +15,5 @@ namespace Juliet
namespace Juliet::Internal namespace Juliet::Internal
{ {
IOStream* IOFromFile(String filename, String mode); IOStream* IOFromFile(NonNullPtr<Arena> arena, String filename, String mode);
} // namespace Juliet::Internal } // namespace Juliet::Internal
@@ -4,7 +4,6 @@
#include <Core/HAL/Win32.h> #include <Core/HAL/Win32.h>
#include <Core/Logging/LogManager.h> #include <Core/Logging/LogManager.h>
#include <Core/Logging/LogTypes.h> #include <Core/Logging/LogTypes.h>
#include <Core/Memory/Allocator.h>
namespace Juliet::Internal namespace Juliet::Internal
{ {
@@ -181,14 +180,12 @@ namespace Juliet::Internal
} }
win32Payload->Handle = INVALID_HANDLE_VALUE; win32Payload->Handle = INVALID_HANDLE_VALUE;
} }
SafeFree(win32Payload->Data);
SafeFree(win32Payload);
return true; return true;
} }
} // namespace } // namespace
IOStream* IOFromFile(String filename, String mode) IOStream* IOFromFile(NonNullPtr<Arena> arena, String filename, String mode)
{ {
// "r" = reading, file must exist // "r" = reading, file must exist
// "w" = writing, truncate existing, file may not exist // "w" = writing, truncate existing, file may not exist
@@ -238,7 +235,7 @@ namespace Juliet::Internal
} }
constexpr bool autoClose = true; constexpr bool autoClose = true;
Win32IOStreamDataPayload* payload = static_cast<Win32IOStreamDataPayload*>(Calloc(1, sizeof(Win32IOStreamDataPayload))); Win32IOStreamDataPayload* payload = ArenaPushStruct<Win32IOStreamDataPayload>(arena);
if (!payload) if (!payload)
{ {
if (autoClose) if (autoClose)
@@ -263,14 +260,14 @@ namespace Juliet::Internal
payload->IsAppending = isAppending; payload->IsAppending = isAppending;
payload->ShouldAutoClose = autoClose; payload->ShouldAutoClose = autoClose;
payload->Data = static_cast<char*>(Malloc(kFileReadBufferSize)); payload->Data = ArenaPushArray<char, false>(arena, kFileReadBufferSize);
if (!payload->Data) if (!payload->Data)
{ {
iface.Close(payload); iface.Close(payload);
return nullptr; return nullptr;
} }
IOStream* stream = IOFromInterface(&iface, payload); IOStream* stream = IOFromInterface(arena, &iface, payload);
if (!stream) if (!stream)
{ {
iface.Close(payload); iface.Close(payload);
+1 -1
View File
@@ -103,7 +103,7 @@ namespace Juliet
{ {
thread_local thread_context* mainThread = nullptr; thread_local thread_context* mainThread = nullptr;
int OS_Main(int argc, wchar_t** argv) int OS_Main([[maybe_unused]] int argc, [[maybe_unused]] wchar_t** argv)
{ {
SetUnhandledExceptionFilter(&ExceptionFilter); SetUnhandledExceptionFilter(&ExceptionFilter);
+5 -13
View File
@@ -9,10 +9,8 @@
namespace Juliet namespace Juliet
{ {
void InitHotReloadCode(HotReloadCode& code, String dllName, String transientDllName, String lockFilename) void InitHotReloadCode(NonNullPtr<Arena> arena, HotReloadCode& code, String dllName, String transientDllName, String lockFilename)
{ {
code.Arena = ArenaAllocate({ .ReserveSize = Megabytes(1), .Name = "Hot Reload" });
// Get the app base path and build the dll path from there. // Get the app base path and build the dll path from there.
String basePath = GetBasePath(); String basePath = GetBasePath();
size_t basePathLength = StringLength(basePath); size_t basePathLength = StringLength(basePath);
@@ -25,12 +23,11 @@ namespace Juliet
const size_t dllFullPathLength = const size_t dllFullPathLength =
basePathLength + StringLength(dllName) + 1; // Need +1 because snprintf needs 0 terminated strings basePathLength + StringLength(dllName) + 1; // Need +1 because snprintf needs 0 terminated strings
code.DLLFullPath.Str = code.DLLFullPath.Str = static_cast<char*>(
static_cast<char*>(ArenaPush(code.Arena, dllFullPathLength, alignof(char), true JULIET_DEBUG_PARAM("DLL Path"))); ArenaPush(arena, dllFullPathLength, alignof(char), true JULIET_DEBUG_PARAM("Hot Reload DLL Path")));
int writtenSize = snprintf(CStr(code.DLLFullPath), dllFullPathLength, "%s%s", CStr(basePath), CStr(dllName)); int writtenSize = snprintf(CStr(code.DLLFullPath), dllFullPathLength, "%s%s", CStr(basePath), CStr(dllName));
if (writtenSize < static_cast<int>(dllFullPathLength) - 1) if (writtenSize < static_cast<int>(dllFullPathLength) - 1)
{ {
// Arena memory persists, no free needed
Log(LogLevel::Error, LogCategory::Core, "Cannot create DLL Full Path"); Log(LogLevel::Error, LogCategory::Core, "Cannot create DLL Full Path");
return; return;
} }
@@ -39,13 +36,12 @@ namespace Juliet
// Lock filename path // Lock filename path
const size_t lockPathLength = const size_t lockPathLength =
basePathLength + StringLength(lockFilename) + 1; // Need +1 because snprintf needs 0 terminated strings basePathLength + StringLength(lockFilename) + 1; // Need +1 because snprintf needs 0 terminated strings
code.LockFullPath.Str = code.LockFullPath.Str = static_cast<char*>(
static_cast<char*>(ArenaPush(code.Arena, lockPathLength, alignof(char), true JULIET_DEBUG_PARAM("Lock File Path"))); ArenaPush(arena, lockPathLength, alignof(char), true JULIET_DEBUG_PARAM("Hot Reload Lock File Path")));
writtenSize = snprintf(CStr(code.LockFullPath), lockPathLength, "%s%s", CStr(basePath), CStr(lockFilename)); writtenSize = snprintf(CStr(code.LockFullPath), lockPathLength, "%s%s", CStr(basePath), CStr(lockFilename));
if (writtenSize < static_cast<int>(lockPathLength) - 1) if (writtenSize < static_cast<int>(lockPathLength) - 1)
{ {
code.LockFullPath.Size = 0; code.LockFullPath.Size = 0;
// Arena memory persists, no free needed
Log(LogLevel::Error, LogCategory::Core, "Cannot create lock file full path"); Log(LogLevel::Error, LogCategory::Core, "Cannot create lock file full path");
return; return;
} }
@@ -59,11 +55,7 @@ namespace Juliet
UnloadCode(code); UnloadCode(code);
code.DLLFullPath.Size = 0; code.DLLFullPath.Size = 0;
// Arena memory persists until engine shutdown
code.LockFullPath.Size = 0; code.LockFullPath.Size = 0;
// Arena memory persists until engine shutdown
ArenaRelease(code.Arena);
} }
void ReloadCode(HotReloadCode& code) void ReloadCode(HotReloadCode& code)
@@ -6,6 +6,7 @@
#include <Core/Logging/LogTypes.h> #include <Core/Logging/LogTypes.h>
#include <Core/Memory/Allocator.h> #include <Core/Memory/Allocator.h>
#include <Core/Memory/MemoryArena.h> #include <Core/Memory/MemoryArena.h>
#include <Core/Thread/ThreadContext.h>
namespace Juliet namespace Juliet
{ {
@@ -31,9 +32,6 @@ namespace Juliet
void LoadCode(HotReloadCode& code) void LoadCode(HotReloadCode& code)
{ {
// TODO : Create and use a TransientAllocator
// Create temp dll name
char* lockFilename = code.LockFullPath.Str; char* lockFilename = code.LockFullPath.Str;
WIN32_FILE_ATTRIBUTE_DATA Ignored; WIN32_FILE_ATTRIBUTE_DATA Ignored;
if (!GetFileAttributesExA(lockFilename, GetFileExInfoStandard, &Ignored)) if (!GetFileAttributesExA(lockFilename, GetFileExInfoStandard, &Ignored))
@@ -56,7 +54,7 @@ namespace Juliet
basePathLength + StringLength(code.TransientDLLName) + /* _ */ 1 + kTempDLLBufferSizeForID + 1 /* \0 */; basePathLength + StringLength(code.TransientDLLName) + /* _ */ 1 + kTempDLLBufferSizeForID + 1 /* \0 */;
// Allocate from Scratch Arena (transient) // Allocate from Scratch Arena (transient)
TempArena temp = ArenaTempBegin(code.Arena); TempArena temp = scratch_begin(0, 0);
auto tempDllPath = ArenaPushArray<char>(temp.Arena, tempDllMaxBufferSize); auto tempDllPath = ArenaPushArray<char>(temp.Arena, tempDllMaxBufferSize);
for (uint32 attempt = 0; attempt < kMaxAttempts; ++attempt) for (uint32 attempt = 0; attempt < kMaxAttempts; ++attempt)
@@ -97,7 +95,7 @@ namespace Juliet
break; break;
} }
} }
ArenaTempEnd(temp); scratch_end(temp);
code.Dll = LoadDynamicLibrary(tempDllPath); code.Dll = LoadDynamicLibrary(tempDllPath);
if (code.Dll) if (code.Dll)
+1 -1
View File
@@ -75,7 +75,7 @@ namespace Juliet::ImGuiService
Assert(!g_Initialized); Assert(!g_Initialized);
// Initialize ImGui Arena using Engine Pool // Initialize ImGui Arena using Engine Pool
g_ImGuiArena = ArenaAllocate({ .Name = "Juliet" }); g_ImGuiArena = ArenaAllocate({ .Name = "Imgui Allocator Arena" });
// Setup Allocator // Setup Allocator
ImGui::SetAllocatorFunctions(ImGuiAllocWrapper, ImGuiFreeWrapper, nullptr); ImGui::SetAllocatorFunctions(ImGuiAllocWrapper, ImGuiFreeWrapper, nullptr);
+7 -4
View File
@@ -4,6 +4,8 @@
#include <Core/Logging/LogManager.h> #include <Core/Logging/LogManager.h>
#include <Core/Logging/LogTypes.h> #include <Core/Logging/LogTypes.h>
#include <Graphics/Graphics.h> #include <Graphics/Graphics.h>
#include <Core/Thread/ThreadContext.h>
#include <Graphics/GraphicsDevice.h> #include <Graphics/GraphicsDevice.h>
namespace Juliet namespace Juliet
@@ -316,21 +318,22 @@ namespace Juliet
// Shaders // Shaders
Shader* CreateShader(NonNullPtr<GraphicsDevice> device, String filename, ShaderCreateInfo& shaderCreateInfo) Shader* CreateShader(NonNullPtr<GraphicsDevice> device, String filename, ShaderCreateInfo& shaderCreateInfo)
{ {
TempArena fileArena = scratch_begin(0, 0);
ByteBuffer shaderByteCode = {}; ByteBuffer shaderByteCode = {};
// Create path from filename // Create path from filename
if (IsAbsolutePath(filename)) if (IsAbsolutePath(filename))
{ {
shaderByteCode = LoadFile(filename); shaderByteCode = LoadFile(fileArena.Arena, filename);
} }
else else
{ {
// TODO: Add path builder in the lib // TODO: Add path builder in the lib
String base = GetBasePath(); String base = GetBasePath();
char inplaceBuffer[256]; char inplaceBuffer[256];
snprintf(inplaceBuffer, sizeof(inplaceBuffer), "%s%s", base.Str, filename.Str); juliet_snprintf(inplaceBuffer, sizeof(inplaceBuffer), "%s%s", base.Str, filename.Str);
String absolutePath = WrapString(inplaceBuffer); String absolutePath = WrapString(inplaceBuffer);
shaderByteCode = LoadFile(absolutePath); shaderByteCode = LoadFile(fileArena.Arena, absolutePath);
} }
if (!IsValid(shaderByteCode)) if (!IsValid(shaderByteCode))
@@ -340,7 +343,7 @@ namespace Juliet
Shader* shader = device->CreateShader(device->Driver, shaderByteCode, shaderCreateInfo JULIET_DEBUG_PARAM(filename)); Shader* shader = device->CreateShader(device->Driver, shaderByteCode, shaderCreateInfo JULIET_DEBUG_PARAM(filename));
Free(shaderByteCode); scratch_end(fileArena);
return shader; return shader;
} }
+2 -2
View File
@@ -106,7 +106,7 @@ namespace
} // namespace } // namespace
void JulietApplication::Init(NonNullPtr<Arena>) void JulietApplication::Init(NonNullPtr<Arena> platformArena)
{ {
Log(LogLevel::Message, LogCategory::Tool, "Initializing Juliet Application..."); Log(LogLevel::Message, LogCategory::Tool, "Initializing Juliet Application...");
Log(LogLevel::Message, LogCategory::Tool, "%s", CStr(GetBasePath())); Log(LogLevel::Message, LogCategory::Tool, "%s", CStr(GetBasePath()));
@@ -182,7 +182,7 @@ void JulietApplication::Init(NonNullPtr<Arena>)
GameCode.Functions = reinterpret_cast<void**>(&Game); GameCode.Functions = reinterpret_cast<void**>(&Game);
GameCode.FunctionCount = ArraySize(GameFunctionTable); GameCode.FunctionCount = ArraySize(GameFunctionTable);
GameCode.FunctionNames = GameFunctionTable; GameCode.FunctionNames = GameFunctionTable;
InitHotReloadCode(GameCode, ConstString("Game.dll"), ConstString("Game_Temp.dll"), ConstString("lock.tmp")); InitHotReloadCode(platformArena, GameCode, ConstString("Game.dll"), ConstString("Game_Temp.dll"), ConstString("lock.tmp"));
Running = GameCode.IsValid; Running = GameCode.IsValid;
} }
} }