From 4180622d6aa45e5a1314c8039c0b3ec404d84e07 Mon Sep 17 00:00:00 2001 From: Patedam Date: Sat, 22 Aug 2026 21:39:21 -0400 Subject: [PATCH] Removing named namespace from code base. --- Game/Controller/DebugCameraController.cpp | 50 +- Game/Debug/DebugTopBar.cpp | 5 +- Game/Entity/Entity.h | 14 +- Game/Entity/EntityManager.cpp | 12 +- Game/Entity/EntityManager.h | 8 +- Game/game.cpp | 6 +- Game/game.h | 6 +- .../Core/Application/ApplicationManager.h | 11 +- .../include/Core/Application/IApplication.h | 49 +- Juliet/include/Core/Common/CRC32.h | 95 +- Juliet/include/Core/Common/CoreUtils.h | 241 +- Juliet/include/Core/Common/EnumUtils.h | 147 +- Juliet/include/Core/Common/NonNullPtr.h | 183 +- Juliet/include/Core/Common/String.h | 277 +- Juliet/include/Core/Container/Vector.h | 367 +- Juliet/include/Core/HAL/Display/Display.h | 21 +- .../include/Core/HAL/DynLib/DynamicLibrary.h | 13 +- Juliet/include/Core/HAL/Event/SystemEvent.h | 189 +- .../include/Core/HAL/Filesystem/Filesystem.h | 25 +- Juliet/include/Core/HAL/IO/IOStream.h | 97 +- Juliet/include/Core/HAL/Keyboard/KeyCode.h | 371 +- Juliet/include/Core/HAL/Keyboard/Keyboard.h | 47 +- Juliet/include/Core/HAL/Keyboard/ScanCode.h | 327 +- Juliet/include/Core/HAL/Mouse/Mouse.h | 45 +- Juliet/include/Core/HAL/OS/OS.h | 73 +- Juliet/include/Core/HotReload/HotReload.h | 49 +- Juliet/include/Core/ImGui/ImGuiService.h | 31 +- Juliet/include/Core/ImGui/ImGuiTests.h | 4 +- Juliet/include/Core/JulietInit.h | 35 +- Juliet/include/Core/Logging/LogManager.h | 29 +- Juliet/include/Core/Logging/LogTypes.h | 35 +- Juliet/include/Core/Main.h | 8 +- Juliet/include/Core/Math/MathUtils.h | 73 +- Juliet/include/Core/Math/Matrix.h | 351 +- Juliet/include/Core/Math/Shape.h | 17 +- Juliet/include/Core/Math/Vector.h | 49 +- Juliet/include/Core/Memory/Allocator.h | 43 +- Juliet/include/Core/Memory/MemoryArena.h | 219 +- Juliet/include/Core/Memory/MemoryArenaDebug.h | 69 +- Juliet/include/Core/Memory/ScratchArena.h | 0 Juliet/include/Core/Memory/Utils.h | 117 +- Juliet/include/Core/Networking/IPAddress.h | 13 +- .../include/Core/Networking/NetworkPacket.h | 47 +- Juliet/include/Core/Networking/Socket.h | 97 +- Juliet/include/Core/Networking/SocketHandle.h | 9 +- Juliet/include/Core/Networking/TcpListener.h | 23 +- Juliet/include/Core/Networking/TcpSocket.h | 31 +- Juliet/include/Core/PCH.h | 2 +- Juliet/include/Core/Thread/Mutex.h | 9 +- Juliet/include/Core/Thread/Thread.h | 23 +- Juliet/include/Core/Thread/ThreadContext.h | 29 +- Juliet/include/Engine/Asset.h | 7 +- Juliet/include/Engine/Class.h | 43 +- Juliet/include/Engine/Debug/MemoryDebugger.h | 6 +- Juliet/include/Engine/Engine.h | 31 +- Juliet/include/Graphics/Camera.h | 55 +- Juliet/include/Graphics/Colors.h | 23 +- Juliet/include/Graphics/DebugDisplay.h | 17 +- Juliet/include/Graphics/Graphics.h | 271 +- Juliet/include/Graphics/GraphicsBuffer.h | 57 +- Juliet/include/Graphics/GraphicsConfig.h | 21 +- Juliet/include/Graphics/GraphicsPipeline.h | 377 +- Juliet/include/Graphics/ImGuiRenderer.h | 13 +- Juliet/include/Graphics/Lighting.h | 17 +- Juliet/include/Graphics/Mesh.h | 53 +- Juliet/include/Graphics/MeshRenderer.h | 79 +- Juliet/include/Graphics/PushConstants.h | 45 +- Juliet/include/Graphics/RenderPass.h | 193 +- Juliet/include/Graphics/Shader.h | 31 +- Juliet/include/Graphics/SkyboxRenderer.h | 33 +- Juliet/include/Graphics/Texture.h | 355 +- Juliet/include/Graphics/VertexData.h | 17 +- .../Core/Application/ApplicationManager.cpp | 19 +- Juliet/src/Core/Common/CoreUtils.cpp | 49 +- Juliet/src/Core/Common/String.cpp | 1147 ++- Juliet/src/Core/Container/Vector.cpp | 5 +- Juliet/src/Core/HAL/Display/Display.cpp | 269 +- Juliet/src/Core/HAL/Display/DisplayDevice.h | 63 +- Juliet/src/Core/HAL/Display/Display_cpp.h | 9 +- .../HAL/Display/Win32/Win32DisplayDevice.cpp | 11 +- .../HAL/Display/Win32/Win32DisplayEvent.cpp | 6 +- .../HAL/Display/Win32/Win32DisplayEvent.h | 11 +- .../Core/HAL/Display/Win32/Win32Window.cpp | 6 +- .../src/Core/HAL/Display/Win32/Win32Window.h | 13 +- Juliet/src/Core/HAL/Display/Window.h | 31 +- .../Core/HAL/DynLib/Win32/DynamicLibrary.cpp | 59 +- Juliet/src/Core/HAL/Event/Keyboard.cpp | 257 +- Juliet/src/Core/HAL/Event/KeyboardMapping.cpp | 385 +- Juliet/src/Core/HAL/Event/KeyboardMapping.h | 9 +- Juliet/src/Core/HAL/Event/Keyboard_Private.h | 11 +- Juliet/src/Core/HAL/Event/Mouse.cpp | 235 +- Juliet/src/Core/HAL/Event/Mouse_Private.h | 39 +- Juliet/src/Core/HAL/Event/SystemEvent.cpp | 133 +- Juliet/src/Core/HAL/Event/Win32ScanCode.h | 6 +- Juliet/src/Core/HAL/Event/WindowEvent.cpp | 23 +- Juliet/src/Core/HAL/Event/WindowEvent.h | 11 +- Juliet/src/Core/HAL/Filesystem/Filesystem.cpp | 163 +- .../Core/HAL/Filesystem/Filesystem_Platform.h | 6 +- .../Core/HAL/Filesystem/Filesystem_Private.h | 9 +- .../HAL/Filesystem/Win32/Win32Filesystem.cpp | 6 +- Juliet/src/Core/HAL/IO/IOStream.cpp | 355 +- Juliet/src/Core/HAL/IO/IOStream_cpp.h | 19 +- .../src/Core/HAL/IO/Win32/Win32IOStream.cpp | 6 +- Juliet/src/Core/HAL/OS/OS.cpp | 141 +- Juliet/src/Core/HAL/OS/OS_Private.h | 43 +- Juliet/src/Core/HAL/OS/Win32/Win32OS.cpp | 225 +- Juliet/src/Core/HotReload/HotReload.cpp | 101 +- .../Core/HotReload/Win32/Win32HotReload.cpp | 227 +- Juliet/src/Core/ImGui/ImGuiService.cpp | 8 +- Juliet/src/Core/ImGui/ImGuiTests.cpp | 6 +- Juliet/src/Core/Juliet.cpp | 87 +- Juliet/src/Core/Logging/LogManager.cpp | 317 +- Juliet/src/Core/Math/MathRound.cpp | 123 +- Juliet/src/Core/Math/Math_Private.h | 69 +- Juliet/src/Core/Memory/Allocator.cpp | 73 +- Juliet/src/Core/Memory/MemoryArena.cpp | 339 +- Juliet/src/Core/Memory/MemoryArenaDebug.cpp | 279 +- Juliet/src/Core/Memory/MemoryArenaTests.cpp | 6 +- Juliet/src/Core/Memory/ScratchArena.cpp | 0 Juliet/src/Core/Networking/NetworkPacket.cpp | 115 +- Juliet/src/Core/Networking/Socket.cpp | 123 +- .../src/Core/Networking/SocketPlatformImpl.h | 6 +- Juliet/src/Core/Networking/TcpListener.cpp | 103 +- Juliet/src/Core/Networking/TcpSocket.cpp | 145 +- .../Win32/Win32SocketPlatformImpl.cpp | 33 +- Juliet/src/Core/PCH.cpp | 2 +- Juliet/src/Core/Thread/ThreadContext.cpp | 119 +- Juliet/src/Core/Thread/win32_thread.cpp | 87 +- Juliet/src/Engine/Asset.cpp | 7 +- Juliet/src/Engine/Debug/MemoryDebugger.cpp | 11 +- Juliet/src/Engine/Engine.cpp | 347 +- Juliet/src/Graphics/Camera.cpp | 107 +- .../Graphics/D3D12/D3D12GraphicsDevice.cpp | 8448 ++++++++--------- Juliet/src/Graphics/DebugDisplayRenderer.cpp | 643 +- Juliet/src/Graphics/Graphics.cpp | 769 +- Juliet/src/Graphics/GraphicsDevice.h | 205 +- Juliet/src/Graphics/ImGuiRenderer.cpp | 709 +- Juliet/src/Graphics/Mesh.cpp | 5 +- Juliet/src/Graphics/MeshRenderer.cpp | 1015 +- Juliet/src/Graphics/SkyboxRenderer.cpp | 185 +- .../src/UnitTest/Container/VectorUnitTest.cpp | 6 +- Juliet/src/UnitTest/RunUnitTests.cpp | 6 +- JulietApp/main.cpp | 7 +- JulietApp/main.h | 39 +- JulietShaderCompiler/ShaderCompiler.cpp | 3 +- JulietShaderCompiler/ShaderCompiler.h | 6 +- JulietShaderCompiler/main.cpp | 3 +- Romeo/src/AiGenerator.cpp | 76 +- Romeo/src/AiGenerator.h | 4 +- Romeo/src/Database.cpp | 52 +- Romeo/src/Database.h | 22 +- Romeo/src/HttpClient.cpp | 20 +- Romeo/src/HttpClient.h | 12 +- Romeo/src/JsonParser.cpp | 22 +- Romeo/src/JsonParser.h | 16 +- Romeo/src/MarkdownGenerator.cpp | 140 +- Romeo/src/MarkdownGenerator.h | 4 +- Romeo/src/main.cpp | 36 +- 158 files changed, 12260 insertions(+), 12648 deletions(-) delete mode 100644 Juliet/include/Core/Memory/ScratchArena.h delete mode 100644 Juliet/src/Core/Memory/ScratchArena.cpp diff --git a/Game/Controller/DebugCameraController.cpp b/Game/Controller/DebugCameraController.cpp index 6ef2207..853d3c4 100644 --- a/Game/Controller/DebugCameraController.cpp +++ b/Game/Controller/DebugCameraController.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -24,10 +24,10 @@ void ActivateDebugController() { Assert(gIsDebugCameraActive == false); - Juliet::Camera* currentCam = Juliet::GetCurrentCamera(); + Camera* currentCam = GetCurrentCamera(); gPreviousCameraIndex = currentCam->Index; - Juliet::SetCurrentCamera(kDebugCamera); + SetCurrentCamera(kDebugCamera); gIsDebugCameraActive = true; gFirstUpdate = true; @@ -41,7 +41,7 @@ void DeactivateDebugController() gIsDebugCameraActive = false; - Juliet::SetCurrentCamera(gPreviousCameraIndex); + SetCurrentCamera(gPreviousCameraIndex); } bool IsDebugControllerActive() @@ -51,26 +51,26 @@ bool IsDebugControllerActive() void UpdateDebugController(float dt) { - Juliet::Camera* currentCam = Juliet::GetCurrentCamera(); + Camera* currentCam = GetCurrentCamera(); if (gFirstUpdate) { - Juliet::Vector3 dir = Juliet::Vector3{ 0.0f, 0.0f, 0.0f } - currentCam->Position; - dir = Juliet::Normalize(dir); + Vector3 dir = Vector3{ 0.0f, 0.0f, 0.0f } - currentCam->Position; + dir = Normalize(dir); gPitch = asinf(dir.z); gYaw = atan2f(dir.y, dir.x); gFirstUpdate = false; - Juliet::Vector3 forward; + Vector3 forward; forward.x = cosf(gPitch) * cosf(gYaw); forward.y = cosf(gPitch) * sinf(gYaw); forward.z = sinf(gPitch); - Juliet::Vector3 right = Juliet::Normalize(Juliet::Cross(Juliet::Vector3{ 0.0f, 0.0f, 1.0f }, forward)); + Vector3 right = Normalize(Cross(Vector3{ 0.0f, 0.0f, 1.0f }, forward)); currentCam->Target = currentCam->Position + forward; - currentCam->Up = Juliet::Cross(forward, right); + currentCam->Up = Cross(forward, right); } - bool isRightMouseButtonDown = Juliet::IsMouseButtonDown(Juliet::MouseButton::Right); + bool isRightMouseButtonDown = IsMouseButtonDown(MouseButton::Right); if (isRightMouseButtonDown && !gWasRightMouseButtonDown) { gIsFpsModeActive = !gIsFpsModeActive; @@ -82,7 +82,7 @@ void UpdateDebugController(float dt) return; } - Juliet::MousePosition mouseDelta = Juliet::GetMouseDelta(); + MousePosition mouseDelta = GetMouseDelta(); float sensitivity = 0.005f; gYaw += mouseDelta.X * sensitivity; @@ -91,52 +91,52 @@ void UpdateDebugController(float dt) gPitch = std::min(gPitch, 1.5f); gPitch = std::max(gPitch, -1.5f); - if (Juliet::IsKeyDown(Juliet::ScanCode::Q)) + if (IsKeyDown(ScanCode::Q)) { gYaw -= 2.0f * dt; } - if (Juliet::IsKeyDown(Juliet::ScanCode::E)) + if (IsKeyDown(ScanCode::E)) { gYaw += 2.0f * dt; } - Juliet::Vector3 forward; + Vector3 forward; forward.x = cosf(gPitch) * cosf(gYaw); forward.y = cosf(gPitch) * sinf(gYaw); forward.z = sinf(gPitch); - Juliet::Vector3 right = Juliet::Normalize(Juliet::Cross(Juliet::Vector3{ 0.0f, 0.0f, 1.0f }, forward)); - Juliet::Vector3 defaultUp = Juliet::Cross(forward, right); + Vector3 right = Normalize(Cross(Vector3{ 0.0f, 0.0f, 1.0f }, forward)); + Vector3 defaultUp = Cross(forward, right); static const float kMovementPerFrame = 10.f; // 10m/s float speedPerFrame = kMovementPerFrame; - if (Juliet::IsKeyDown(Juliet::ScanCode::LeftShift)) + if (IsKeyDown(ScanCode::LeftShift)) { speedPerFrame *= 10.f; // 100m/s } - if (Juliet::IsKeyDown(Juliet::ScanCode::W)) + if (IsKeyDown(ScanCode::W)) { currentCam->Position = currentCam->Position + forward * (speedPerFrame * dt); } - if (Juliet::IsKeyDown(Juliet::ScanCode::S)) + if (IsKeyDown(ScanCode::S)) { currentCam->Position = currentCam->Position - forward * (speedPerFrame * dt); } - if (Juliet::IsKeyDown(Juliet::ScanCode::D)) + if (IsKeyDown(ScanCode::D)) { currentCam->Position = currentCam->Position + right * (speedPerFrame * dt); } - if (Juliet::IsKeyDown(Juliet::ScanCode::A)) + if (IsKeyDown(ScanCode::A)) { currentCam->Position = currentCam->Position - right * (speedPerFrame * dt); } - if (Juliet::IsKeyDown(Juliet::ScanCode::Space)) + if (IsKeyDown(ScanCode::Space)) { currentCam->Position = currentCam->Position + defaultUp * (speedPerFrame * dt); } - if (Juliet::IsKeyDown(Juliet::ScanCode::LeftControl)) + if (IsKeyDown(ScanCode::LeftControl)) { currentCam->Position = currentCam->Position - defaultUp * (speedPerFrame * dt); } @@ -148,7 +148,7 @@ void UpdateDebugController(float dt) #if JULIET_DEBUG void RenderImGuiDebugController(float dt) { - Juliet::Camera* currentCam = Juliet::GetCurrentCamera(); + Camera* currentCam = GetCurrentCamera(); ImGui::Text("Delta time: %f", dt); diff --git a/Game/Debug/DebugTopBar.cpp b/Game/Debug/DebugTopBar.cpp index 61991d2..23a1102 100644 --- a/Game/Debug/DebugTopBar.cpp +++ b/Game/Debug/DebugTopBar.cpp @@ -1,13 +1,12 @@ -#include +#include #include #include namespace { - Juliet::String GetGameModeName(GameMode gameMode) + String GetGameModeName(GameMode gameMode) { - using namespace Juliet; switch (gameMode) { case GameMode::Editor: return WrapString("Editor"); diff --git a/Game/Entity/Entity.h b/Game/Entity/Entity.h index 62ede4f..7abbc2a 100644 --- a/Game/Entity/Entity.h +++ b/Game/Entity/Entity.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -8,19 +8,19 @@ #define DECLARE_ENTITY() \ Entity* Base; \ - static const Juliet::Class* Kind; + static const Class* Kind; // Will register the class globally at launch #define DEFINE_ENTITY(entity) \ - constexpr Juliet::Class entityKind##entity(#entity, sizeof(#entity) / sizeof(char)); \ - const Juliet::Class* entity::Kind = &entityKind##entity; + constexpr Class entityKind##entity(#entity, sizeof(#entity) / sizeof(char)); \ + const Class* entity::Kind = &entityKind##entity; using DerivedType = void*; struct Entity final { EntityID ID; - const Juliet::Class* Kind; + const Class* Kind; DerivedType Derived; float X, Y; index_t MeshInstance = indexMax; @@ -28,7 +28,7 @@ struct Entity final template concept EntityConcept = requires(EntityType entity) { - requires std::same_as; + requires std::same_as; requires std::same_as; }; @@ -44,7 +44,7 @@ template EntityType* MakeEntity(EntityManager& manager, float x, float y) { auto* arena = manager.Arena; - EntityType* result = Juliet::ArenaPushStruct(arena); + EntityType* result = ArenaPushStruct(arena); Entity base; base.X = x; base.Y = y; diff --git a/Game/Entity/EntityManager.cpp b/Game/Entity/EntityManager.cpp index d640be6..c234c06 100644 --- a/Game/Entity/EntityManager.cpp +++ b/Game/Entity/EntityManager.cpp @@ -1,18 +1,18 @@ -#include +#include #include #include EntityID EntityManager::ID = 0; -void InitEntityManager(Juliet::NonNullPtr world) +void InitEntityManager(NonNullPtr world) { - EntityManager* newManager = Juliet::ArenaPushStruct(world->WorldArena); + EntityManager* newManager = ArenaPushStruct(world->WorldArena); world->EntityManager = newManager; newManager->Entities.Create(world->WorldArena JULIET_DEBUG_PARAM("Entities")); - newManager->Arena = Juliet::ArenaAllocate({ .Name = "Entity Arena" }); + newManager->Arena = ArenaAllocate({ .Name = "Entity Arena" }); } void ShutdownEntityManager() @@ -22,7 +22,7 @@ void ShutdownEntityManager() EntityManager& GetEntityManager() { - Juliet::NonNullPtr entityManager = GetGameState()->World->EntityManager; + NonNullPtr entityManager = GetGameState()->World->EntityManager; return *entityManager; } @@ -37,7 +37,7 @@ void UpdateEntityManager(EntityManager& manager) { if (ent.MeshInstance != indexMax) { - Juliet::SetMeshInstanceTransform(ent.MeshInstance, Juliet::MatrixTranslation(ent.X, ent.Y, 0.0f)); + SetMeshInstanceTransform(ent.MeshInstance, MatrixTranslation(ent.X, ent.Y, 0.0f)); } } } diff --git a/Game/Entity/EntityManager.h b/Game/Entity/EntityManager.h index 0a212ae..0de4c7b 100644 --- a/Game/Entity/EntityManager.h +++ b/Game/Entity/EntityManager.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -11,13 +11,13 @@ struct EntityManager { static EntityID ID; - Juliet::Arena* Arena; + Arena* Arena; // TODO: Should be a pool - Juliet::VectorArena Entities; + VectorArena Entities; }; -void InitEntityManager(Juliet::NonNullPtr world); +void InitEntityManager(NonNullPtr world); void ShutdownEntityManager(); EntityManager& GetEntityManager(); void RegisterEntity(EntityManager& manager, Entity* entity); diff --git a/Game/game.cpp b/Game/game.cpp index cee50c0..c095921 100644 --- a/Game/game.cpp +++ b/Game/game.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -31,14 +31,12 @@ extern "C" JULIET_API void __cdecl GameShutdown() { printf("Shutting down game...\n"); - using namespace Juliet; ShutdownEntityManager(); } -extern "C" JULIET_API void __cdecl GameUpdate(Juliet::GameData* params, [[maybe_unused]] float deltaTime) +extern "C" JULIET_API void __cdecl GameUpdate(GameData* params, [[maybe_unused]] float deltaTime) { - using namespace Juliet; gGameState = params->GameState; if (!gGameState) diff --git a/Game/game.h b/Game/game.h index 66bc767..8546a68 100644 --- a/Game/game.h +++ b/Game/game.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include @@ -6,7 +6,7 @@ struct EntityManager; struct World { - Juliet::Arena* WorldArena; + Arena* WorldArena; EntityManager* EntityManager; }; @@ -19,7 +19,7 @@ enum class GameMode struct GameState { - Juliet::Arena* TotalArena; + Arena* TotalArena; World* World; diff --git a/Juliet/include/Core/Application/ApplicationManager.h b/Juliet/include/Core/Application/ApplicationManager.h index 3666f35..d1848a0 100644 --- a/Juliet/include/Core/Application/ApplicationManager.h +++ b/Juliet/include/Core/Application/ApplicationManager.h @@ -1,13 +1,10 @@ -#pragma once +#pragma once #include #include #include -namespace Juliet -{ - enum class JulietInit_Flags : uint8; +enum class JulietInit_Flags : uint8; - struct Arena; - extern JULIET_API void StartApplication(IApplication& app, JulietInit_Flags flags); -} // namespace Juliet +struct Arena; +extern JULIET_API void StartApplication(IApplication& app, JulietInit_Flags flags); diff --git a/Juliet/include/Core/Application/IApplication.h b/Juliet/include/Core/Application/IApplication.h index 07b9214..595c4c4 100644 --- a/Juliet/include/Core/Application/IApplication.h +++ b/Juliet/include/Core/Application/IApplication.h @@ -1,32 +1,29 @@ -#pragma once +#pragma once #include -namespace Juliet +struct Camera; +struct RenderPass; +struct CommandList; +struct Texture; +struct ColorTargetInfo; +struct DepthStencilTargetInfo; +struct Arena; + +class IApplication { - struct Camera; - struct RenderPass; - struct CommandList; - struct Texture; - struct ColorTargetInfo; - struct DepthStencilTargetInfo; - struct Arena; + public: + virtual ~IApplication() = default; + virtual void Init(NonNullPtr arena) = 0; + virtual void Shutdown() = 0; + virtual void Update(float deltaTime) = 0; + virtual bool IsRunning() = 0; - class IApplication - { - public: - virtual ~IApplication() = default; - virtual void Init(NonNullPtr arena) = 0; - virtual void Shutdown() = 0; - virtual void Update(float deltaTime) = 0; - virtual bool IsRunning() = 0; + // Accessors for Engine Systems + virtual struct Window* GetPlatformWindow() = 0; + virtual struct GraphicsDevice* GetGraphicsDevice() = 0; - // Accessors for Engine Systems - virtual struct Window* GetPlatformWindow() = 0; - virtual struct GraphicsDevice* GetGraphicsDevice() = 0; - - // Render Lifecycle (Engine-Managed Render Loop) - virtual ColorTargetInfo GetColorTargetInfo(Texture* swapchainTexture) = 0; - virtual DepthStencilTargetInfo* GetDepthTargetInfo() = 0; - }; -} // namespace Juliet + // Render Lifecycle (Engine-Managed Render Loop) + virtual ColorTargetInfo GetColorTargetInfo(Texture* swapchainTexture) = 0; + virtual DepthStencilTargetInfo* GetDepthTargetInfo() = 0; +}; diff --git a/Juliet/include/Core/Common/CRC32.h b/Juliet/include/Core/Common/CRC32.h index 3cc2403..d6be052 100644 --- a/Juliet/include/Core/Common/CRC32.h +++ b/Juliet/include/Core/Common/CRC32.h @@ -1,58 +1,55 @@ -#pragma once +#pragma once // From https://web.mit.edu/freebsd/head/sys/libkern/crc32.c -namespace Juliet +namespace details { - namespace details - { - constexpr uint32_t crc32_tab[] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, - 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, - 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, - 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, - 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, - 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, - 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, - 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, - 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, - 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, - 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, - 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, - 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, - 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, - 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d - }; - } + constexpr uint32_t crc32_tab[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, + 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, + 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, + 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, + 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, + 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, + 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, + 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, + 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, + 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, + 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, + 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d + }; +} - consteval uint32 crc32(const char* str, size_t length) +consteval uint32 crc32(const char* str, size_t length) +{ + const char* p = str; + uint32_t crc = ~0U; + while (length--) { - const char* p = str; - uint32_t crc = ~0U; - while (length--) - { - crc = details::crc32_tab[(crc ^ static_cast(*p++)) & 0xFF] ^ (crc >> 8); - } - return crc ^ ~0U; + crc = details::crc32_tab[(crc ^ static_cast(*p++)) & 0xFF] ^ (crc >> 8); } + return crc ^ ~0U; +} - consteval uint32 operator""_crc32(const char* str, size_t length) - { - return crc32(str, length); - } +consteval uint32 operator""_crc32(const char* str, size_t length) +{ + return crc32(str, length); +} -} // namespace Juliet diff --git a/Juliet/include/Core/Common/CoreUtils.h b/Juliet/include/Core/Common/CoreUtils.h index 5c5ce40..fd04ee6 100644 --- a/Juliet/include/Core/Common/CoreUtils.h +++ b/Juliet/include/Core/Common/CoreUtils.h @@ -1,18 +1,16 @@ -#pragma once +#pragma once #include #include -namespace Juliet -{ #define global static - // 1. Stringify helpers +// 1. Stringify helpers #define JULIET_STR(x) #x #define JULIET_TOSTRING(x) JULIET_STR(x) - // 2. Define the pragma operator based on compiler +// 2. Define the pragma operator based on compiler #if defined(__clang__) || defined(__GNUC__) #define JULIET_PRAGMA(x) _Pragma(#x) #define JULIET_SUPPRESS_MSVC(id) @@ -27,7 +25,7 @@ namespace Juliet #define JULIET_SUPPRESS_CLANG(str) #endif - // 3. The Agnostic "Push/Pop" +// 3. The Agnostic "Push/Pop" #if defined(__clang__) #define JULIET_WARNING_PUSH JULIET_PRAGMA(clang diagnostic push) #define JULIET_WARNING_POP JULIET_PRAGMA(clang diagnostic pop) @@ -40,10 +38,10 @@ namespace Juliet #endif #if defined(_MSC_VER) - // MSVC specific intrinsic +// MSVC specific intrinsic #define JULIET_PLATFORM_BREAK() (__nop(), __debugbreak()) #elif defined(__clang__) || defined(__GNUC__) - // Clang/GCC specific intrinsic +// Clang/GCC specific intrinsic #define JULIET_PLATFORM_BREAK() __builtin_trap() #else #include @@ -52,40 +50,40 @@ namespace Juliet #if JULIET_DEBUG #define JULIET_ASSERT_INTERNAL(expression, message) \ - JULIET_WARNING_PUSH \ - JULIET_SUPPRESS_CLANG("-Wextra-semi-stmt") \ - JULIET_SUPPRESS_MSVC(4127) \ - JULIET_SUPPRESS_MSVC(4548) \ - { \ - if (!(expression)) [[unlikely]] \ - { \ - Juliet::JulietAssert(#expression, message); \ - } \ - } \ - JULIET_WARNING_POP \ - static_assert(true, "") +JULIET_WARNING_PUSH \ +JULIET_SUPPRESS_CLANG("-Wextra-semi-stmt") \ +JULIET_SUPPRESS_MSVC(4127) \ +JULIET_SUPPRESS_MSVC(4548) \ +{ \ + if (!(expression)) [[unlikely]] \ + { \ + JulietAssert(#expression, message); \ + } \ +} \ +JULIET_WARNING_POP \ +static_assert(true, "") #define AssertHR(hr_expression, message) \ - do \ - { \ - long hr_val = (hr_expression); \ - if (hr_val < 0) \ - { \ - Juliet::JulietAssert(#hr_expression, message, std::source_location::current(), hr_val); \ - } \ - } \ - while (0) +do \ +{ \ + long hr_val = (hr_expression); \ + if (hr_val < 0) \ + { \ + JulietAssert(#hr_expression, message, std::source_location::current(), hr_val); \ + } \ +} \ +while (0) #define GET_ASSERT_MACRO(_1, _2, NAME, ...) NAME #define Assert(...) GET_ASSERT_MACRO(__VA_ARGS__, JULIET_ASSERT_INTERNAL, JULIET_ASSERT_NO_MSG)(__VA_ARGS__) #define JULIET_ASSERT_NO_MSG(expression) JULIET_ASSERT_INTERNAL(expression, "No additional information provided.") #define Unimplemented() \ - do \ - { \ - Juliet::JulietAssert("UNIMPLEMENTED", "This code path is not yet functional."); \ - } \ - while (0) +do \ +{ \ + JulietAssert("UNIMPLEMENTED", "This code path is not yet functional."); \ +} \ +while (0) #else #define Assert(...) ((void)0) @@ -93,85 +91,85 @@ namespace Juliet #define Unimplemented() ((void)0) #endif - JULIET_API extern void JulietAssert(const char* expression, const char* message, - std::source_location location = std::source_location::current(), long handleResult = 0); +JULIET_API extern void JulietAssert(const char* expression, const char* message, + std::source_location location = std::source_location::current(), long handleResult = 0); #define ZeroStruct(structInstance) ZeroSize(sizeof(structInstance), &(structInstance)) #define ZeroArray(array) ZeroSize(sizeof((array)), (array)) #define ZeroDynArray(Count, Pointer) ZeroSize((Count) * sizeof((Pointer)[0]), Pointer) - inline void ZeroSize(size_t size, void* ptr) +inline void ZeroSize(size_t size, void* ptr) +{ + auto Byte = (uint8*)ptr; + while (size--) { - auto Byte = (uint8*)ptr; - while (size--) - { - *Byte++ = 0; - } + *Byte++ = 0; } +} #define Restrict __restrict - template - class DeferredFunction +template +class DeferredFunction +{ + public: + explicit DeferredFunction(const Function& otherFct) noexcept + : Callback(otherFct) { - public: - explicit DeferredFunction(const Function& otherFct) noexcept - : Callback(otherFct) - { - } - explicit DeferredFunction(Function&& otherFct) noexcept - : Callback(std::move(otherFct)) - { - } - - ~DeferredFunction() noexcept { Callback(); } - - DeferredFunction(const DeferredFunction&) = delete; - DeferredFunction(const DeferredFunction&&) = delete; - void operator=(const DeferredFunction&) = delete; - void operator=(DeferredFunction&&) = delete; - - private: - Function Callback; - }; - - template - auto Defer(Function&& fct) noexcept + } + explicit DeferredFunction(Function&& otherFct) noexcept + : Callback(std::move(otherFct)) { - return DeferredFunction>{ std::forward(fct) }; } - inline bool IsValid(ByteBuffer buffer) - { - return buffer.Size > 0 && buffer.Data; - } + ~DeferredFunction() noexcept { Callback(); } - extern JULIET_API void Free(ByteBuffer& buffer); + DeferredFunction(const DeferredFunction&) = delete; + DeferredFunction(const DeferredFunction&&) = delete; + void operator=(const DeferredFunction&) = delete; + void operator=(DeferredFunction&&) = delete; - template - [[nodiscard]] constexpr T AlignPow2(T x, T alignment) - { - // Safety Check: - Assert(std::has_single_bit(static_cast(alignment))); + private: + Function Callback; +}; - return (x + alignment - 1) & ~(alignment - 1); - } +template +auto Defer(Function&& fct) noexcept +{ + return DeferredFunction>{ std::forward(fct) }; +} - template - inline void Swap(T* Restrict a, T* Restrict b) - { - T temp = std::move(*a); - *a = std::move(*b); - *b = std::move(temp); - } +inline bool IsValid(ByteBuffer buffer) +{ + return buffer.Size > 0 && buffer.Data; +} - // Move to another file dedicated to those +extern JULIET_API void Free(ByteBuffer& buffer); + +template +[[nodiscard]] constexpr T AlignPow2(T x, T alignment) +{ + // Safety Check: + Assert(std::has_single_bit(static_cast(alignment))); + + return (x + alignment - 1) & ~(alignment - 1); +} + +template +inline void Swap(T* Restrict a, T* Restrict b) +{ + T temp = std::move(*a); + *a = std::move(*b); + *b = std::move(temp); +} + +// Move to another file dedicated to those #if defined(__clang__) #define COMPILER_CLANG 1 #elif defined(_MSC_VER) #define COMPILER_MSVC 1 #endif - // Undef anything not defined +// Undef anything not defined #if !defined(COMPILER_CLANG) #define COMPILER_CLANG 0 #endif @@ -189,43 +187,42 @@ namespace Juliet #error AlignOf not defined for this compiler. #endif - template - [[nodiscard]] constexpr const char* GetTypeName() - { +template +[[nodiscard]] constexpr const char* GetTypeName() +{ #if COMPILER_CLANG - return __PRETTY_FUNCTION__; + return __PRETTY_FUNCTION__; #elif COMPILER_MSVC - return __FUNCSIG__; + return __FUNCSIG__; #elif COMPILER_GCC - return __PRETTY_FUNCTION__; + return __PRETTY_FUNCTION__; #else - return "UnknownType"; + return "UnknownType"; #endif - } +} - inline uint16 safe_cast_uint16(uint32 value) - { - Assert(value <= uint16Max); - uint16 result = (uint16)value; - return result; - } +inline uint16 safe_cast_uint16(uint32 value) +{ + Assert(value <= uint16Max); + uint16 result = (uint16)value; + return result; +} - const uint32 bitmask1 = 0b0000'0001; - const uint32 bitmask2 = 0b0000'0011; - const uint32 bitmask3 = 0b0000'0111; - const uint32 bitmask4 = 0b0000'1111; - const uint32 bitmask5 = 0b0001'1111; - const uint32 bitmask6 = 0b0011'1111; - const uint32 bitmask7 = 0b0111'1111; - const uint32 bitmask8 = 0b1111'1111; - const uint32 bitmask9 = 0x0000'01ff; - const uint32 bitmask10 = 0x0000'03ff; - const uint32 bitmask11 = 0x0000'07ff; - const uint32 bitmask12 = 0x0000'0fff; - const uint32 bitmask13 = 0x0000'1fff; - const uint32 bitmask14 = 0x0000'3fff; - const uint32 bitmask15 = 0x0000'7fff; - const uint32 bitmask16 = 0x0000'ffff; - // ... - const uint32 bitmask32 = 0xffff'ffff; -} // namespace Juliet +const uint32 bitmask1 = 0b0000'0001; +const uint32 bitmask2 = 0b0000'0011; +const uint32 bitmask3 = 0b0000'0111; +const uint32 bitmask4 = 0b0000'1111; +const uint32 bitmask5 = 0b0001'1111; +const uint32 bitmask6 = 0b0011'1111; +const uint32 bitmask7 = 0b0111'1111; +const uint32 bitmask8 = 0b1111'1111; +const uint32 bitmask9 = 0x0000'01ff; +const uint32 bitmask10 = 0x0000'03ff; +const uint32 bitmask11 = 0x0000'07ff; +const uint32 bitmask12 = 0x0000'0fff; +const uint32 bitmask13 = 0x0000'1fff; +const uint32 bitmask14 = 0x0000'3fff; +const uint32 bitmask15 = 0x0000'7fff; +const uint32 bitmask16 = 0x0000'ffff; +// ... +const uint32 bitmask32 = 0xffff'ffff; diff --git a/Juliet/include/Core/Common/EnumUtils.h b/Juliet/include/Core/Common/EnumUtils.h index 207f9da..80d2480 100644 --- a/Juliet/include/Core/Common/EnumUtils.h +++ b/Juliet/include/Core/Common/EnumUtils.h @@ -1,89 +1,86 @@ -#pragma once +#pragma once -namespace Juliet +template +concept IsEnum = std::is_enum_v; + +template +constexpr E operator~(E lhs) noexcept { - template - concept IsEnum = std::is_enum_v; + return static_cast(~static_cast>(lhs)); +} - template - constexpr E operator~(E lhs) noexcept - { - return static_cast(~static_cast>(lhs)); - } +template +constexpr E operator|(E lhs, E rhs) noexcept +{ + return static_cast(static_cast>(lhs) | static_cast>(rhs)); +} - template - constexpr E operator|(E lhs, E rhs) noexcept - { - return static_cast(static_cast>(lhs) | static_cast>(rhs)); - } +template +constexpr E& operator|=(E& lhs, E rhs) noexcept +{ + return lhs = (lhs | rhs); +} - template - constexpr E& operator|=(E& lhs, E rhs) noexcept - { - return lhs = (lhs | rhs); - } +template +constexpr E operator&(E lhs, E rhs) noexcept +{ + return static_cast(static_cast>(lhs) & static_cast>(rhs)); +} - template - constexpr E operator&(E lhs, E rhs) noexcept - { - return static_cast(static_cast>(lhs) & static_cast>(rhs)); - } +template +constexpr E& operator&=(E& lhs, E rhs) noexcept +{ + return lhs = (lhs & rhs); +} - template - constexpr E& operator&=(E& lhs, E rhs) noexcept - { - return lhs = (lhs & rhs); - } +template +constexpr E operator^(E lhs, E rhs) noexcept +{ + return static_cast(static_cast>(lhs) ^ static_cast>(rhs)); +} - template - constexpr E operator^(E lhs, E rhs) noexcept - { - return static_cast(static_cast>(lhs) ^ static_cast>(rhs)); - } +template +constexpr E& operator^=(E& lhs, E rhs) noexcept +{ + return lhs = (lhs ^ rhs); +} - template - constexpr E& operator^=(E& lhs, E rhs) noexcept - { - return lhs = (lhs ^ rhs); - } +template +constexpr std::underlying_type_t operator-(E lhs, E rhs) noexcept +{ + using T = std::underlying_type_t; + return static_cast(static_cast(lhs) - static_cast(rhs)); +} - template - constexpr std::underlying_type_t operator-(E lhs, E rhs) noexcept - { - using T = std::underlying_type_t; - return static_cast(static_cast(lhs) - static_cast(rhs)); - } +template +constexpr std::underlying_type_t operator+(E lhs, E rhs) noexcept +{ + using T = std::underlying_type_t; + return static_cast(static_cast(lhs) + static_cast(rhs)); +} - template - constexpr std::underlying_type_t operator+(E lhs, E rhs) noexcept - { - using T = std::underlying_type_t; - return static_cast(static_cast(lhs) + static_cast(rhs)); - } +template +constexpr E operator-(E lhs, std::underlying_type_t rhs) noexcept +{ + using T = std::underlying_type_t; + return static_cast(static_cast(static_cast(lhs) - rhs)); +} - template - constexpr E operator-(E lhs, std::underlying_type_t rhs) noexcept - { - using T = std::underlying_type_t; - return static_cast(static_cast(static_cast(lhs) - rhs)); - } +template +constexpr E operator+(E lhs, std::underlying_type_t rhs) noexcept +{ + using T = std::underlying_type_t; + return static_cast(static_cast(static_cast(lhs) + rhs)); +} - template - constexpr E operator+(E lhs, std::underlying_type_t rhs) noexcept - { - using T = std::underlying_type_t; - return static_cast(static_cast(static_cast(lhs) + rhs)); - } +template +constexpr std::underlying_type_t ToUnderlying(E enm) noexcept +{ + return static_cast>(enm); +} - template - constexpr std::underlying_type_t ToUnderlying(E enm) noexcept - { - return static_cast>(enm); - } - - template - constexpr E ToEnum(std::underlying_type_t value) noexcept - { - return static_cast(value); - } -} // namespace Juliet +template +constexpr E ToEnum(std::underlying_type_t value) noexcept +{ + return static_cast(value); +} diff --git a/Juliet/include/Core/Common/NonNullPtr.h b/Juliet/include/Core/Common/NonNullPtr.h index d6ff890..85ccaee 100644 --- a/Juliet/include/Core/Common/NonNullPtr.h +++ b/Juliet/include/Core/Common/NonNullPtr.h @@ -1,113 +1,110 @@ -#pragma once +#pragma once #include -namespace Juliet +template +concept NonNullPtr_Convertible = std::is_convertible_v; + +template +concept NonNullPtr_SameType = std::is_same_v; + +template +class NonNullPtr { - template - concept NonNullPtr_Convertible = std::is_convertible_v; - - template - concept NonNullPtr_SameType = std::is_same_v; - - template - class NonNullPtr + public: + constexpr NonNullPtr(Type* ptr) + : InternalPtr(ptr) { - public: - constexpr NonNullPtr(Type* ptr) - : InternalPtr(ptr) - { - Assert(ptr, "Tried to initialize a NonNullPtr with a null pointer"); - } + Assert(ptr, "Tried to initialize a NonNullPtr with a null pointer"); + } - template - requires NonNullPtr_Convertible - constexpr NonNullPtr(const NonNullPtr& otherPtr) - : InternalPtr(otherPtr.Get()) - { - Assert(InternalPtr, "Fatal Error: Assigned a non null ptr using another NonNullPtr but its was null."); - } + template + requires NonNullPtr_Convertible + constexpr NonNullPtr(const NonNullPtr& otherPtr) + : InternalPtr(otherPtr.Get()) + { + Assert(InternalPtr, "Fatal Error: Assigned a non null ptr using another NonNullPtr but its was null."); + } - // Assignment - [[nodiscard]] constexpr NonNullPtr& operator=(Type* ptr) - { - Assert(ptr, "Tried to assign a null pointer to a NonNullPtr!"); - InternalPtr = ptr; - return *this; - } + // Assignment + [[nodiscard]] constexpr NonNullPtr& operator=(Type* ptr) + { + Assert(ptr, "Tried to assign a null pointer to a NonNullPtr!"); + InternalPtr = ptr; + return *this; + } - template - requires NonNullPtr_Convertible - [[nodiscard]] constexpr NonNullPtr& operator=(const NonNullPtr& otherPtr) - { - InternalPtr = otherPtr.Get(); - return *this; - } + template + requires NonNullPtr_Convertible + [[nodiscard]] constexpr NonNullPtr& operator=(const NonNullPtr& otherPtr) + { + InternalPtr = otherPtr.Get(); + return *this; + } - // Accessors - [[nodiscard]] constexpr operator Type*() const - { - Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null"); - return InternalPtr; - } + // Accessors + [[nodiscard]] constexpr operator Type*() const + { + Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null"); + return InternalPtr; + } - [[nodiscard]] constexpr Type* Get() const - { - Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null"); - return InternalPtr; - } + [[nodiscard]] constexpr Type* Get() const + { + Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null"); + return InternalPtr; + } - [[nodiscard]] constexpr Type& operator*() const - { - Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null"); - return *InternalPtr; - } + [[nodiscard]] constexpr Type& operator*() const + { + Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null"); + return *InternalPtr; + } - [[nodiscard]] constexpr Type* operator->() const - { - Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null"); - return InternalPtr; - } + [[nodiscard]] constexpr Type* operator->() const + { + Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null"); + return InternalPtr; + } - // Comparisons - [[nodiscard]] constexpr bool operator==(const NonNullPtr& otherPtr) const - { - return InternalPtr == otherPtr.InternalPtr; - } + // Comparisons + [[nodiscard]] constexpr bool operator==(const NonNullPtr& otherPtr) const + { + return InternalPtr == otherPtr.InternalPtr; + } - template - requires NonNullPtr_SameType - [[nodiscard]] constexpr bool operator==(OtherType* otherRawPtr) const - { - return InternalPtr == otherRawPtr; - } + template + requires NonNullPtr_SameType + [[nodiscard]] constexpr bool operator==(OtherType* otherRawPtr) const + { + return InternalPtr == otherRawPtr; + } - template - requires NonNullPtr_SameType - [[nodiscard]] constexpr friend bool operator==(OtherType* otherRawPtr, const NonNullPtr& nonNullPtr) - { - return otherRawPtr == nonNullPtr.InternalPtr; - } + template + requires NonNullPtr_SameType + [[nodiscard]] constexpr friend bool operator==(OtherType* otherRawPtr, const NonNullPtr& nonNullPtr) + { + return otherRawPtr == nonNullPtr.InternalPtr; + } - // Forbid assigning a nullptr at compile time - constexpr NonNullPtr(std::nullptr_t) - : InternalPtr(nullptr) - { - static_assert(sizeof(Type) == 0, "Trying to initialize a NonNullPtr with a nullptr value"); - } + // Forbid assigning a nullptr at compile time + constexpr NonNullPtr(std::nullptr_t) + : InternalPtr(nullptr) + { + static_assert(sizeof(Type) == 0, "Trying to initialize a NonNullPtr with a nullptr value"); + } - [[nodiscard]] constexpr NonNullPtr& operator=(std::nullptr_t) - { - static_assert(sizeof(Type) == 0, "Trying to assign a NonNullPtr with a nullptr value"); - return *this; - } + [[nodiscard]] constexpr NonNullPtr& operator=(std::nullptr_t) + { + static_assert(sizeof(Type) == 0, "Trying to assign a NonNullPtr with a nullptr value"); + return *this; + } - [[nodiscard]] constexpr explicit operator bool() const { return InternalPtr != nullptr; } + [[nodiscard]] constexpr explicit operator bool() const { return InternalPtr != nullptr; } - private: - Type* InternalPtr; - }; + private: + Type* InternalPtr; +}; - template - NonNullPtr(T*) -> NonNullPtr; -} // namespace Juliet +template +NonNullPtr(T*) -> NonNullPtr; diff --git a/Juliet/include/Core/Common/String.h b/Juliet/include/Core/Common/String.h index 62b983c..d6293c1 100644 --- a/Juliet/include/Core/Common/String.h +++ b/Juliet/include/Core/Common/String.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -14,170 +14,167 @@ #undef RESTORE_GLOBAL #endif -namespace Juliet -{ - struct Arena; +struct Arena; #define ConstString(str) { const_cast((str)), sizeof(str) - 1 } #define CStr(str) ((str).Str) #define InplaceString(name, size) \ - char name##_[size]; \ - MemSet(name##_, 0, sizeof(uint32)); \ - String name = { name##_, 0 } +char name##_[size]; \ +MemSet(name##_, 0, sizeof(uint32)); \ +String name = { name##_, 0 } - // Everything is Little Endian - enum class StringEncoding : uint8 +// Everything is Little Endian +enum class StringEncoding : uint8 +{ + Unknown = 0, + ASCII, + LATIN1, + UTF8, + UTF16, + UTF32, + UCS2, + UCS4, +}; + +// Represents a UTF-8 String. +// Not null terminated. +struct String8 +{ + char* Str; + size_t Size; +}; +using String = String8; + +struct String16 +{ + uint16* Str; + size_t Size; +}; + +struct StringBuffer : String +{ + size_t Capacity; +}; + +struct UnicodeDecode +{ + uint32 Increment; + uint32 Codepoint; +}; + +constexpr uint32 kInvalidUTF8 = 0xFFFD; + +inline size_t StringLength(String str) +{ + return str.Size; +} + +inline size_t StringLength(const char* str) +{ + size_t length = 0; + if (str) { - Unknown = 0, - ASCII, - LATIN1, - UTF8, - UTF16, - UTF32, - UCS2, - UCS4, - }; - - // Represents a UTF-8 String. - // Not null terminated. - struct String8 - { - char* Str; - size_t Size; - }; - using String = String8; - - struct String16 - { - uint16* Str; - size_t Size; - }; - - struct StringBuffer : String - { - size_t Capacity; - }; - - struct UnicodeDecode - { - uint32 Increment; - uint32 Codepoint; - }; - - constexpr uint32 kInvalidUTF8 = 0xFFFD; - - inline size_t StringLength(String str) - { - return str.Size; - } - - inline size_t StringLength(const char* str) - { - size_t length = 0; - if (str) + while (*str) { - while (*str) - { - ++length; - ++str; - } + ++length; + ++str; } - - return length; } - inline bool IsValid(String str) - { - return str.Size > 0 && str.Str != nullptr && *str.Str; - } + return length; +} - inline String WrapString(const char* str) - { - String result = {}; - result.Str = const_cast(str); - result.Size = str ? strlen(str) : 0; - return result; - } +inline bool IsValid(String str) +{ + return str.Size > 0 && str.Str != nullptr && *str.Str; +} - inline String FindChar(String str, char c) +inline String WrapString(const char* str) +{ + String result = {}; + result.Str = const_cast(str); + result.Size = str ? strlen(str) : 0; + return result; +} + +inline String FindChar(String str, char c) +{ + String result = str; + while (result.Size) { - String result = str; - while (result.Size) + if (*result.Str != c) { - if (*result.Str != c) - { - ++result.Str; - --result.Size; - } - else - { - return result; - } + ++result.Str; + --result.Size; } - return {}; - } - - inline bool ContainsChar(String str, char c) - { - return IsValid(FindChar(str, c)); - } - - // Return: - // - < 0 if str1 < str2 - // - = 0 : Both strings are equals - // - > 0 if str1 > str2 - inline int32 StringCompare(String str1, String str2) - { - size_t len1 = StringLength(str1); - size_t len2 = StringLength(str2); - size_t minLen = Min(len1, len2); - int32 result = MemCompare(CStr(str1), CStr(str2), minLen); - if (result == 0) + else { - if (len1 > len2) - { - return 1; - } - if (len1 < len2) - { - return -1; - } - return 0; + return result; } - return result; } + return {}; +} - JULIET_API uint32 StepUTF8(String& inStr); - JULIET_API String FindString(String strLeft, String strRight); +inline bool ContainsChar(String str, char c) +{ + return IsValid(FindChar(str, c)); +} - // Case insensitive compare. Supports ASCII only - // TODO: Support UNICODE - extern JULIET_API int8 StringCompareCaseInsensitive(String str1, String str2); - - // Do not allocate anything, you must allocate your out buffer yourself - // TODO: Version taking arena that can allocate - // Do not take String type because we dont know the string encoding we are going from/to - // src and dst will be casted based on the encoding. - // size will correspond to the number of characters - // Will convert \0 character if present. - extern JULIET_API bool ConvertString(StringEncoding from, StringEncoding to, String src, StringBuffer& dst, bool nullTerminate); - extern JULIET_API bool ConvertString(String from, String to, String src, StringBuffer& dst, bool nullTerminate); - - JULIET_API String StringCopy(NonNullPtr arena, String str); - JULIET_API String16 str16_from_8(NonNullPtr arena, String8 str); - - template - String Format(NonNullPtr arena, const char* formatStr, Args&&... args) +// Return: +// - < 0 if str1 < str2 +// - = 0 : Both strings are equals +// - > 0 if str1 > str2 +inline int32 StringCompare(String str1, String str2) +{ + size_t len1 = StringLength(str1); + size_t len2 = StringLength(str2); + size_t minLen = Min(len1, len2); + int32 result = MemCompare(CStr(str1), CStr(str2), minLen); + if (result == 0) { - std::string result = std::vformat(formatStr, std::make_format_args(args...)); - return StringCopy(arena, WrapString(result.c_str())); + if (len1 > len2) + { + return 1; + } + if (len1 < len2) + { + return -1; + } + return 0; } + return result; +} + +JULIET_API uint32 StepUTF8(String& inStr); +JULIET_API String FindString(String strLeft, String strRight); + +// Case insensitive compare. Supports ASCII only +// TODO: Support UNICODE +extern JULIET_API int8 StringCompareCaseInsensitive(String str1, String str2); + +// Do not allocate anything, you must allocate your out buffer yourself +// TODO: Version taking arena that can allocate +// Do not take String type because we dont know the string encoding we are going from/to +// src and dst will be casted based on the encoding. +// size will correspond to the number of characters +// Will convert \0 character if present. +extern JULIET_API bool ConvertString(StringEncoding from, StringEncoding to, String src, StringBuffer& dst, bool nullTerminate); +extern JULIET_API bool ConvertString(String from, String to, String src, StringBuffer& dst, bool nullTerminate); + +JULIET_API String StringCopy(NonNullPtr arena, String str); +JULIET_API String16 str16_from_8(NonNullPtr arena, String8 str); + +template +String Format(NonNullPtr arena, const char* formatStr, Args&&... args) +{ + std::string result = std::vformat(formatStr, std::make_format_args(args...)); + return StringCopy(arena, WrapString(result.c_str())); +} #define juliet_snprintf snprintf -} // namespace Juliet #ifdef UNIT_TEST -namespace Juliet::UnitTest +namespace UnitTest { inline void TestFindChar() { @@ -192,5 +189,5 @@ namespace Juliet::UnitTest Assert(FindChar(s2, 'f').Str - s2.Str == 5); Assert(FindChar(s3, '1').Str - s3.Str == 0); } -} // namespace Juliet::UnitTest +} // namespace UnitTest #endif diff --git a/Juliet/include/Core/Container/Vector.h b/Juliet/include/Core/Container/Vector.h index 094aae4..5031ffe 100644 --- a/Juliet/include/Core/Container/Vector.h +++ b/Juliet/include/Core/Container/Vector.h @@ -1,214 +1,211 @@ -#pragma once +#pragma once #include #include -namespace Juliet +template +struct VectorArena { - template - struct VectorArena + void Create(NonNullPtr arena JULIET_DEBUG_PARAM(const char* name = nullptr)) { - void Create(NonNullPtr arena JULIET_DEBUG_PARAM(const char* name = nullptr)) + Assert(!Arena); + + JULIET_DEBUG_ONLY(Name = name ? name : Name;) + + DataFirst = DataLast = Data = nullptr; + Count = 0; + Capacity = 0; + Arena = arena; + + Reserve(ReserveSize); + } + + void Destroy() + { + DataFirst = DataLast = Data = nullptr; + Count = 0; + Capacity = 0; + Arena = nullptr; + } + + void Reserve(size_t newCapacity) + { + Assert(Arena); + Assert(newCapacity <= ReserveSize && "VectorArena capacity should be <= ReserveSize."); + + if (Data == nullptr) { - Assert(!Arena); + Data = ArenaPushArray(Arena, newCapacity JULIET_DEBUG_PARAM(Name)); + Capacity = newCapacity; + } + else + { + Unimplemented(); + } + } - JULIET_DEBUG_ONLY(Name = name ? name : Name;) + void Resize(size_t newCount) + { + Assert(Arena); + if (newCount == Count) + { + return; + } - DataFirst = DataLast = Data = nullptr; - Count = 0; - Capacity = 0; - Arena = arena; + if (Data == nullptr) + { + size_t initialCapacity = newCount > ReserveSize ? newCount : ReserveSize; + Reserve(initialCapacity); + } + Assert(newCount <= Capacity && "VectorArena capacity exceeded!"); + Count = newCount; + + if (Count > 0) + { + DataFirst = Data; + DataLast = Data + Count - 1; + } + else + { + DataFirst = DataLast = nullptr; + } + } + + void PushBack(const Type* buffer, size_t amount) + { + Assert(Arena); + Assert(buffer || amount == 0); + + if (amount == 0) + { + return; + } + + if (Data == nullptr) + { + size_t initialCapacity = amount > ReserveSize ? amount : ReserveSize; + Reserve(initialCapacity); + } + + Assert(Count + amount <= Capacity && "VectorArena capacity exceeded!"); + + Type* dst = Data + Count; + MemCopy(dst, buffer, amount * sizeof(Type)); + + if (Count == 0) + { + DataFirst = dst; + } + DataLast = dst + amount - 1; + Count += amount; + } + + void PushBack(const Type& value) + { + Assert(Arena); + + if (Data == nullptr) + { Reserve(ReserveSize); } - void Destroy() + Assert(Count + 1 <= Capacity && "VectorArena capacity exceeded!"); + + Type* entry = Data + Count; + *entry = value; + + if (Count == 0) { - DataFirst = DataLast = Data = nullptr; - Count = 0; - Capacity = 0; - Arena = nullptr; + DataFirst = entry; + } + DataLast = entry; + ++Count; + } + + void PushBack(Type&& value) + { + Assert(Arena); + + if (Data == nullptr) + { + Reserve(ReserveSize); } - void Reserve(size_t newCapacity) - { - Assert(Arena); - Assert(newCapacity <= ReserveSize && "VectorArena capacity should be <= ReserveSize."); + Assert(Count + 1 <= Capacity && "VectorArena capacity exceeded!"); - if (Data == nullptr) - { - Data = ArenaPushArray(Arena, newCapacity JULIET_DEBUG_PARAM(Name)); - Capacity = newCapacity; - } - else - { - Unimplemented(); - } + Type* entry = Data + Count; + *entry = std::move(value); + + if (Count == 0) + { + DataFirst = entry; + } + DataLast = entry; + ++Count; + } + + void RemoveAtFast(index_t index) + { + Assert(Arena); + Assert(index < Count); + Assert(Count > 0); + + Type* elementAdr = DataFirst + index; + + // Swap DataLast and element + if (DataLast != elementAdr) + { + Swap(DataLast, elementAdr); } - void Resize(size_t newCount) + --DataLast; + --Count; + + if (Count == 0) { - Assert(Arena); - if (newCount == Count) - { - return; - } - - if (Data == nullptr) - { - size_t initialCapacity = newCount > ReserveSize ? newCount : ReserveSize; - Reserve(initialCapacity); - } - - Assert(newCount <= Capacity && "VectorArena capacity exceeded!"); - Count = newCount; - - if (Count > 0) - { - DataFirst = Data; - DataLast = Data + Count - 1; - } - else - { - DataFirst = DataLast = nullptr; - } - } - - void PushBack(const Type* buffer, size_t amount) - { - Assert(Arena); - Assert(buffer || amount == 0); - - if (amount == 0) - { - return; - } - - if (Data == nullptr) - { - size_t initialCapacity = amount > ReserveSize ? amount : ReserveSize; - Reserve(initialCapacity); - } - - Assert(Count + amount <= Capacity && "VectorArena capacity exceeded!"); - - Type* dst = Data + Count; - MemCopy(dst, buffer, amount * sizeof(Type)); - - if (Count == 0) - { - DataFirst = dst; - } - DataLast = dst + amount - 1; - Count += amount; - } - - void PushBack(const Type& value) - { - Assert(Arena); - - if (Data == nullptr) - { - Reserve(ReserveSize); - } - - Assert(Count + 1 <= Capacity && "VectorArena capacity exceeded!"); - - Type* entry = Data + Count; - *entry = value; - - if (Count == 0) - { - DataFirst = entry; - } - DataLast = entry; - ++Count; - } - - void PushBack(Type&& value) - { - Assert(Arena); - - if (Data == nullptr) - { - Reserve(ReserveSize); - } - - Assert(Count + 1 <= Capacity && "VectorArena capacity exceeded!"); - - Type* entry = Data + Count; - *entry = std::move(value); - - if (Count == 0) - { - DataFirst = entry; - } - DataLast = entry; - ++Count; - } - - void RemoveAtFast(index_t index) - { - Assert(Arena); - Assert(index < Count); - Assert(Count > 0); - - Type* elementAdr = DataFirst + index; - - // Swap DataLast and element - if (DataLast != elementAdr) - { - Swap(DataLast, elementAdr); - } - - --DataLast; - --Count; - - if (Count == 0) - { - DataFirst = DataLast = nullptr; - } - } - - void Clear() - { - Assert(Arena); - DataFirst = DataLast = nullptr; - Count = 0; } + } - [[nodiscard]] bool IsEmpty() const { return Count == 0; } + void Clear() + { + Assert(Arena); - // C++ Accessors for loop supports and Index based access - [[nodiscard]] Type& operator[](size_t index) { return DataFirst[index]; } - [[nodiscard]] const Type& operator[](size_t index) const { return DataFirst[index]; } + DataFirst = DataLast = nullptr; + Count = 0; + } - [[nodiscard]] Type* begin() { return DataFirst; } - [[nodiscard]] Type* end() { return DataFirst + Count; } + [[nodiscard]] bool IsEmpty() const { return Count == 0; } - [[nodiscard]] const Type* begin() const { return DataFirst; } - [[nodiscard]] const Type* end() const { return DataFirst + Count; } + // C++ Accessors for loop supports and Index based access + [[nodiscard]] Type& operator[](size_t index) { return DataFirst[index]; } + [[nodiscard]] const Type& operator[](size_t index) const { return DataFirst[index]; } - [[nodiscard]] Type* First() { return DataFirst; } - [[nodiscard]] Type* Front() { return DataFirst; } - [[nodiscard]] Type* Last() { return DataLast; } - [[nodiscard]] Type* Back() { return DataLast; } - [[nodiscard]] Type* DataPtr() { return Data; } - [[nodiscard]] const Type* DataPtr() const { return Data; } + [[nodiscard]] Type* begin() { return DataFirst; } + [[nodiscard]] Type* end() { return DataFirst + Count; } - [[nodiscard]] size_t Size() const { return Count; } + [[nodiscard]] const Type* begin() const { return DataFirst; } + [[nodiscard]] const Type* end() const { return DataFirst + Count; } - Arena* Arena = nullptr; - Type* DataFirst = nullptr; - Type* DataLast = nullptr; - Type* Data = nullptr; - size_t Count = 0; - size_t Capacity = 0; - JULIET_DEBUG_ONLY(const char* Name = "VectorArena";) - }; - static_assert(std::is_standard_layout_v>, - "VectorArena must have a standard layout to remain POD-like."); - static_assert(std::is_trivially_copyable_v>, - "VectorArena must be trivially copyable (no custom destructors/assignment)."); -} // namespace Juliet + [[nodiscard]] Type* First() { return DataFirst; } + [[nodiscard]] Type* Front() { return DataFirst; } + [[nodiscard]] Type* Last() { return DataLast; } + [[nodiscard]] Type* Back() { return DataLast; } + [[nodiscard]] Type* DataPtr() { return Data; } + [[nodiscard]] const Type* DataPtr() const { return Data; } + + [[nodiscard]] size_t Size() const { return Count; } + + Arena* Arena = nullptr; + Type* DataFirst = nullptr; + Type* DataLast = nullptr; + Type* Data = nullptr; + size_t Count = 0; + size_t Capacity = 0; + JULIET_DEBUG_ONLY(const char* Name = "VectorArena";) +}; +static_assert(std::is_standard_layout_v>, + "VectorArena must have a standard layout to remain POD-like."); +static_assert(std::is_trivially_copyable_v>, + "VectorArena must be trivially copyable (no custom destructors/assignment)."); diff --git a/Juliet/include/Core/HAL/Display/Display.h b/Juliet/include/Core/HAL/Display/Display.h index ded2705..b1ca2f5 100644 --- a/Juliet/include/Core/HAL/Display/Display.h +++ b/Juliet/include/Core/HAL/Display/Display.h @@ -1,21 +1,18 @@ -#pragma once +#pragma once #include #include #include #include -namespace Juliet -{ - struct Window; +struct Window; - using WindowID = uint8; - extern JULIET_API Window* CreatePlatformWindow(const char* title, uint16 width, uint16 height, int flags = 0 /* unused */); - extern JULIET_API void DestroyPlatformWindow(NonNullPtr window); +using WindowID = uint8; +extern JULIET_API Window* CreatePlatformWindow(const char* title, uint16 width, uint16 height, int flags = 0 /* unused */); +extern JULIET_API void DestroyPlatformWindow(NonNullPtr window); - extern JULIET_API void ShowWindow(NonNullPtr window); - extern JULIET_API void HideWindow(NonNullPtr window); +extern JULIET_API void ShowWindow(NonNullPtr window); +extern JULIET_API void HideWindow(NonNullPtr window); - extern JULIET_API WindowID GetWindowID(NonNullPtr window); - extern JULIET_API void SetWindowTitle(NonNullPtr window, String title); -} // namespace Juliet +extern JULIET_API WindowID GetWindowID(NonNullPtr window); +extern JULIET_API void SetWindowTitle(NonNullPtr window, String title); diff --git a/Juliet/include/Core/HAL/DynLib/DynamicLibrary.h b/Juliet/include/Core/HAL/DynLib/DynamicLibrary.h index 7d6e10e..9d7535b 100644 --- a/Juliet/include/Core/HAL/DynLib/DynamicLibrary.h +++ b/Juliet/include/Core/HAL/DynLib/DynamicLibrary.h @@ -1,12 +1,9 @@ -#pragma once +#pragma once #include -namespace Juliet -{ - struct DynamicLibrary; +struct DynamicLibrary; - extern JULIET_API DynamicLibrary* LoadDynamicLibrary(const char* filename); - extern JULIET_API FunctionPtr LoadFunction(NonNullPtr lib, const char* functionName); - extern JULIET_API void UnloadDynamicLibrary(NonNullPtr lib); -} // namespace Juliet +extern JULIET_API DynamicLibrary* LoadDynamicLibrary(const char* filename); +extern JULIET_API FunctionPtr LoadFunction(NonNullPtr lib, const char* functionName); +extern JULIET_API void UnloadDynamicLibrary(NonNullPtr lib); diff --git a/Juliet/include/Core/HAL/Event/SystemEvent.h b/Juliet/include/Core/HAL/Event/SystemEvent.h index e0b17fd..f219471 100644 --- a/Juliet/include/Core/HAL/Event/SystemEvent.h +++ b/Juliet/include/Core/HAL/Event/SystemEvent.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -9,115 +9,112 @@ // Handles all events from systems handling the Hardware // Very inspired by SDL3 -namespace Juliet +enum class EventType : uint32 { - enum class EventType : uint32 - { - None = 0, - First = None, + None = 0, + First = None, - // Application Events - // User querying an exit - Application_Exit = 100, - // OS terminating the application - Application_OS_Terminate, - Application_Begin = Application_Exit, - Application_End = Application_OS_Terminate, + // Application Events + // User querying an exit + Application_Exit = 100, + // OS terminating the application + Application_OS_Terminate, + Application_Begin = Application_Exit, + Application_End = Application_OS_Terminate, - // Window Events - Window_Close_Request = 200, - Window_Begin = Window_Close_Request, - Window_End = Window_Close_Request, + // Window Events + Window_Close_Request = 200, + Window_Begin = Window_Close_Request, + Window_End = Window_Close_Request, - // Keyboard Event - Key_Down = 300, - Key_Up, - Keyboard_Begin = Key_Down, - Keyboard_End = Key_Up, + // Keyboard Event + Key_Down = 300, + Key_Up, + Keyboard_Begin = Key_Down, + Keyboard_End = Key_Up, - // Mouse Event - Mouse_Move = 400, - Mouse_ButtonPressed, - Mouse_ButtonReleased, + // Mouse Event + Mouse_Move = 400, + Mouse_ButtonPressed, + Mouse_ButtonReleased, - Mouse_Begin = Mouse_Move, - Mouse_End = Mouse_ButtonReleased, + Mouse_Begin = Mouse_Move, + Mouse_End = Mouse_ButtonReleased, - Last // Get value from the previous one - }; + Last // Get value from the previous one +}; - struct WindowEvent - { - WindowID AssociatedWindowID; - uint32 DataPadding[2]; // TODO : define how much data param we need - }; +struct WindowEvent +{ + WindowID AssociatedWindowID; + uint32 DataPadding[2]; // TODO : define how much data param we need +}; - struct KeyboardEvent - { - KeyboardID AssociatedKeyboardID; - WindowID WindowID; - Key Key; - KeyState KeyState; - KeyMod KeyModeState; - }; +struct KeyboardEvent +{ + KeyboardID AssociatedKeyboardID; + WindowID WindowID; + Key Key; + KeyState KeyState; + KeyMod KeyModeState; +}; - // ===================================================== - // Mouse Events - // ===================================================== - struct MouseMovementEvent - { - MouseID AssociatedMouseID; - WindowID WindowID; - float X; - float Y; - float X_Displacement; - float Y_Displacement; - MouseButton ButtonState; - }; +// ===================================================== +// Mouse Events +// ===================================================== +struct MouseMovementEvent +{ + MouseID AssociatedMouseID; + WindowID WindowID; + float X; + float Y; + float X_Displacement; + float Y_Displacement; + MouseButton ButtonState; +}; - struct MouseButtonEvent - { - MouseID AssociatedMouseID; - WindowID WindowID; - float X; - float Y; - MouseButton ButtonState; - bool IsPressed : 1; - }; +struct MouseButtonEvent +{ + MouseID AssociatedMouseID; + WindowID WindowID; + float X; + float Y; + MouseButton ButtonState; + bool IsPressed : 1; +}; - // Tagged union representing ALL possible system events + a bit of data for custom event if needed - union AllSystemEventUnion - { - WindowEvent Window; - KeyboardEvent Keyboard; - MouseMovementEvent MouseMovement; - MouseButtonEvent MouseButton; - uint8 Padding[128]; // Make sure that the union is fixed in size and big enough on all platforms. - }; - // Make sure we do not bust the union size - static_assert(sizeof(AllSystemEventUnion) == sizeof(((AllSystemEventUnion*)nullptr)->Padding)); +// Tagged union representing ALL possible system events + a bit of data for custom event if needed +union AllSystemEventUnion +{ + WindowEvent Window; + KeyboardEvent Keyboard; + MouseMovementEvent MouseMovement; + MouseButtonEvent MouseButton; + uint8 Padding[128]; // Make sure that the union is fixed in size and big enough on all platforms. +}; +// Make sure we do not bust the union size +static_assert(sizeof(AllSystemEventUnion) == sizeof(((AllSystemEventUnion*)nullptr)->Padding)); - struct SystemEvent - { - EventType Type; - uint64 Timestamp; - AllSystemEventUnion Data; - }; +struct SystemEvent +{ + EventType Type; + uint64 Timestamp; + AllSystemEventUnion Data; +}; - // Poll for any event, return false if no event is available. - // Equivalent to WaitEvent(event, 0); - // Will not block - extern JULIET_API bool GetEvent(SystemEvent& event); +// Poll for any event, return false if no event is available. +// Equivalent to WaitEvent(event, 0); +// Will not block +extern JULIET_API bool GetEvent(SystemEvent& event); - // TODO : use chrono to tag the timeout correctly with nanosec - // timeout == -1 means wait for any event before pursuing - // timeout == 0 means checking once for the frame and getting out - // timeout > 0 means wait until time is out - extern JULIET_API bool WaitEvent(SystemEvent& event, int32 timeoutInNS = -1); +// TODO : use chrono to tag the timeout correctly with nanosec +// timeout == -1 means wait for any event before pursuing +// timeout == 0 means checking once for the frame and getting out +// timeout > 0 means wait until time is out +extern JULIET_API bool WaitEvent(SystemEvent& event, int32 timeoutInNS = -1); - // Add an event onto the event queue. - // TODO : support array of events - extern JULIET_API bool AddEvent(SystemEvent& event); +// Add an event onto the event queue. +// TODO : support array of events +extern JULIET_API bool AddEvent(SystemEvent& event); - extern void Events_NewFrame(float deltaTime); -} // namespace Juliet +extern void Events_NewFrame(float deltaTime); diff --git a/Juliet/include/Core/HAL/Filesystem/Filesystem.h b/Juliet/include/Core/HAL/Filesystem/Filesystem.h index 69ac737..0bfbad9 100644 --- a/Juliet/include/Core/HAL/Filesystem/Filesystem.h +++ b/Juliet/include/Core/HAL/Filesystem/Filesystem.h @@ -1,20 +1,17 @@ -#pragma once +#pragma once #include -namespace Juliet -{ - // Returns the path to the application directory - [[nodiscard]] extern JULIET_API String GetBasePath(); +// Returns the path to the application directory +[[nodiscard]] extern JULIET_API String GetBasePath(); - // Returns the resolved base path to the compiled shaders directory. - // In dev, this resolves to ../../Assets/compiled/ relative to the exe. - // In shipping, this resolves to Assets/Shaders/ next to the exe. - [[nodiscard]] extern JULIET_API String GetAssetBasePath(); +// Returns the resolved base path to the compiled shaders directory. +// In dev, this resolves to ../../Assets/compiled/ relative to the exe. +// In shipping, this resolves to Assets/Shaders/ next to the exe. +[[nodiscard]] extern JULIET_API String GetAssetBasePath(); - // Builds a full path to an asset file given its filename (e.g. "Triangle.vert.dxil"). - // The caller owns the returned buffer and must free it. - [[nodiscard]] extern JULIET_API String GetAssetPath(NonNullPtr arena, String filename); +// Builds a full path to an asset file given its filename (e.g. "Triangle.vert.dxil"). +// The caller owns the returned buffer and must free it. +[[nodiscard]] extern JULIET_API String GetAssetPath(NonNullPtr arena, String filename); - [[nodiscard]] extern JULIET_API bool IsAbsolutePath(String path); -} // namespace Juliet +[[nodiscard]] extern JULIET_API bool IsAbsolutePath(String path); diff --git a/Juliet/include/Core/HAL/IO/IOStream.h b/Juliet/include/Core/HAL/IO/IOStream.h index 378b25c..c4bfb2e 100644 --- a/Juliet/include/Core/HAL/IO/IOStream.h +++ b/Juliet/include/Core/HAL/IO/IOStream.h @@ -1,69 +1,66 @@ -#pragma once +#pragma once #include #include #include -namespace Juliet +// Opaque type +struct IOStream; + +struct IOStreamDataPayload { - // Opaque type - struct IOStream; +}; - struct IOStreamDataPayload - { - }; +enum class IOStreamStatus : uint8 +{ + Ready, + Error, + EndOfFile, + NotReady, + ReadOnly, + WriteOnly +}; - enum class IOStreamStatus : uint8 - { - Ready, - Error, - EndOfFile, - NotReady, - ReadOnly, - WriteOnly - }; +enum class IOStreamSeekPivot : uint8 +{ + Begin, + Current, + End, + Count +}; - enum class IOStreamSeekPivot : uint8 - { - Begin, - Current, - End, - Count - }; +// IOStream can be opened on a file or memory, or anything else. +// Use the interface to make it transparent to the user. +struct IOStreamInterface +{ + uint32 Version; - // IOStream can be opened on a file or memory, or anything else. - // Use the interface to make it transparent to the user. - struct IOStreamInterface - { - uint32 Version; + int64 (*Size)(NonNullPtr data); - int64 (*Size)(NonNullPtr data); + int64 (*Seek)(NonNullPtr data, int64 offset, IOStreamSeekPivot pivot); + size_t (*Read)(NonNullPtr data, void* outBuffer, size_t size, NonNullPtr status); + size_t (*Write)(NonNullPtr data, ByteBuffer inBuffer, NonNullPtr status); + bool (*Flush)(NonNullPtr data, NonNullPtr status); - int64 (*Seek)(NonNullPtr data, int64 offset, IOStreamSeekPivot pivot); - size_t (*Read)(NonNullPtr data, void* outBuffer, size_t size, NonNullPtr status); - size_t (*Write)(NonNullPtr data, ByteBuffer inBuffer, NonNullPtr status); - bool (*Flush)(NonNullPtr data, NonNullPtr status); + bool (*Close)(NonNullPtr data); +}; - bool (*Close)(NonNullPtr data); - }; +extern JULIET_API IOStream* IOFromFile(NonNullPtr arena, String filename, String mode); - extern JULIET_API IOStream* IOFromFile(NonNullPtr arena, String filename, String mode); +// Let you use an interface to open any io. Is used internally by IOFromFile +extern JULIET_API IOStream* IOFromInterface(NonNullPtr arena, NonNullPtr streamInterface, + NonNullPtr payload); - // Let you use an interface to open any io. Is used internally by IOFromFile - extern JULIET_API IOStream* IOFromInterface(NonNullPtr arena, NonNullPtr streamInterface, - NonNullPtr payload); +// Write formatted string into the stream. +extern JULIET_API size_t IOPrintf(NonNullPtr stream, _Printf_format_string_ const char* format, ...); +extern JULIET_API size_t IOWrite(NonNullPtr stream, ByteBuffer inBuffer); - // Write formatted string into the stream. - extern JULIET_API size_t IOPrintf(NonNullPtr stream, _Printf_format_string_ const char* format, ...); - extern JULIET_API size_t IOWrite(NonNullPtr stream, ByteBuffer inBuffer); +extern JULIET_API size_t IORead(NonNullPtr stream, void* ptr, size_t size); +extern JULIET_API int64 IOSeek(NonNullPtr stream, int64 offset, IOStreamSeekPivot pivot); - extern JULIET_API size_t IORead(NonNullPtr stream, void* ptr, size_t size); - extern JULIET_API int64 IOSeek(NonNullPtr stream, int64 offset, IOStreamSeekPivot pivot); +extern JULIET_API int64 IOSize(NonNullPtr stream); - extern JULIET_API int64 IOSize(NonNullPtr stream); +extern JULIET_API ByteBuffer LoadFile(NonNullPtr arena, String filename); +extern JULIET_API ByteBuffer LoadFile(NonNullPtr arena, NonNullPtr stream, bool closeStreamWhenDone); - extern JULIET_API ByteBuffer LoadFile(NonNullPtr arena, String filename); - extern JULIET_API ByteBuffer LoadFile(NonNullPtr arena, NonNullPtr stream, bool closeStreamWhenDone); - - extern JULIET_API bool IOClose(NonNullPtr stream); -} // namespace Juliet +extern JULIET_API bool IOClose(NonNullPtr stream); diff --git a/Juliet/include/Core/HAL/Keyboard/KeyCode.h b/Juliet/include/Core/HAL/Keyboard/KeyCode.h index 3f0f465..3791edb 100644 --- a/Juliet/include/Core/HAL/Keyboard/KeyCode.h +++ b/Juliet/include/Core/HAL/Keyboard/KeyCode.h @@ -1,193 +1,190 @@ -#pragma once +#pragma once #include -namespace Juliet +// Represents a Virtual Key corresponding to the Physical key, but localized using the keyboard layout +// ScanCode reprensent US ASCII Keyboard +// WASD Scan codes are ZQSD in KeyCode for French keyboard +// We use the ASCII value of the generated character as value, when possible. +// Keys that do not produce a character are converted to an abritrary value high enough to not conflict +// Reference: https://www.asciitable.com/ +// Reference: https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-6.0/aa299374(v=vs.60) +enum class KeyCode : uint32 { - // Represents a Virtual Key corresponding to the Physical key, but localized using the keyboard layout - // ScanCode reprensent US ASCII Keyboard - // WASD Scan codes are ZQSD in KeyCode for French keyboard - // We use the ASCII value of the generated character as value, when possible. - // Keys that do not produce a character are converted to an abritrary value high enough to not conflict - // Reference: https://www.asciitable.com/ - // Reference: https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-6.0/aa299374(v=vs.60) - enum class KeyCode : uint32 - { - Unknown = 0x0, // 0 - Unsupported = 0x0, // 0 - Return = 0X0Du, // '\r' - Escape = 0X1Bu, // '\X1B' - Backspace = 0X08u, // '\b' - Tab = 0X09u, // '\t' - Space = 0X20u, // ' ' - ExclamationPoint = 0X21u, // '!' - DoubleApostrophe = 0X22u, // '"' - Hash = 0X23u, // '#' - Dollar = 0X24u, // '$' - Percent = 0X25u, // '%' - Ampersand = 0X26u, // '&' - Apostrophe = 0X27u, // '\'' - LeftParenthesis = 0X28u, // '(' - RightParenthesis = 0X29u, // ')' - Asterisk = 0X2Au, // '*' - Plus = 0X2Bu, // '+' - Comma = 0X2Cu, // ',' - Minus = 0X2Du, // '-' - Period = 0X2Eu, // '.' - Slash = 0X2Fu, // '/' - Num0 = 0X30u, // '0' - Num1 = 0X31u, // '1' - Num2 = 0X32u, // '2' - Num3 = 0X33u, // '3' - Num4 = 0X34u, // '4' - Num5 = 0X35u, // '5' - Num6 = 0X36u, // '6' - Num7 = 0X37u, // '7' - Num8 = 0X38u, // '8' - Num9 = 0X39u, // '9' - Colon = 0X3Au, // ':' - Semicolon = 0X3Bu, // ';' - LessThan = 0X3Cu, // '<' - Equals = 0X3Du, // '=' - GreaterThan = 0X3Eu, // '>' - QuestionMark = 0X3Fu, // '?' - CommercialAt = 0x40u, // '@' - LeftBracket = 0X5Bu, // '[' - Backslash = 0X5Cu, // '\\' - RightBracket = 0X5DU, // ']' - Caret = 0X5Eu, // '^' - Underscore = 0X5Fu, // '_' - GraveAccent = 0X60u, // '`' - A = 0x61u, // 'a' - B = 0x62u, // 'b' - C = 0x63u, // 'c' - D = 0x64u, // 'd' - E = 0x65u, // 'e' - F = 0x66u, // 'f' - G = 0x67u, // 'g' - H = 0x68u, // 'h' - I = 0x69u, // 'i' - J = 0x6Au, // 'j' - K = 0x6Bu, // 'k' - L = 0x6CU, // 'l' - M = 0x6DU, // 'm' - N = 0x6Eu, // 'n' - O = 0x6Fu, // 'o' - P = 0x70u, // 'p' - Q = 0x71u, // 'q' - R = 0x72u, // 'r' - S = 0x73u, // 's' - T = 0x74u, // 't' - U = 0x75u, // 'y' - V = 0x76u, // 'v' - W = 0x77u, // 'w' - X = 0x78u, // 'x' - Y = 0x79u, // 'y' - Z = 0x7Au, // 'z' - LeftBrace = 0x7BU, // '{' - Pipe = 0x7CU, // '|' - RightBrace = 0x7DU, // '}' - Tilde = 0x7Eu, // '~' - Delete = 0x7Fu, // '\x7F' - PlusMinus = 0xb1u, // '\xB1' + Unknown = 0x0, // 0 + Unsupported = 0x0, // 0 + Return = 0X0Du, // '\r' + Escape = 0X1Bu, // '\X1B' + Backspace = 0X08u, // '\b' + Tab = 0X09u, // '\t' + Space = 0X20u, // ' ' + ExclamationPoint = 0X21u, // '!' + DoubleApostrophe = 0X22u, // '"' + Hash = 0X23u, // '#' + Dollar = 0X24u, // '$' + Percent = 0X25u, // '%' + Ampersand = 0X26u, // '&' + Apostrophe = 0X27u, // '\'' + LeftParenthesis = 0X28u, // '(' + RightParenthesis = 0X29u, // ')' + Asterisk = 0X2Au, // '*' + Plus = 0X2Bu, // '+' + Comma = 0X2Cu, // ',' + Minus = 0X2Du, // '-' + Period = 0X2Eu, // '.' + Slash = 0X2Fu, // '/' + Num0 = 0X30u, // '0' + Num1 = 0X31u, // '1' + Num2 = 0X32u, // '2' + Num3 = 0X33u, // '3' + Num4 = 0X34u, // '4' + Num5 = 0X35u, // '5' + Num6 = 0X36u, // '6' + Num7 = 0X37u, // '7' + Num8 = 0X38u, // '8' + Num9 = 0X39u, // '9' + Colon = 0X3Au, // ':' + Semicolon = 0X3Bu, // ';' + LessThan = 0X3Cu, // '<' + Equals = 0X3Du, // '=' + GreaterThan = 0X3Eu, // '>' + QuestionMark = 0X3Fu, // '?' + CommercialAt = 0x40u, // '@' + LeftBracket = 0X5Bu, // '[' + Backslash = 0X5Cu, // '\\' + RightBracket = 0X5DU, // ']' + Caret = 0X5Eu, // '^' + Underscore = 0X5Fu, // '_' + GraveAccent = 0X60u, // '`' + A = 0x61u, // 'a' + B = 0x62u, // 'b' + C = 0x63u, // 'c' + D = 0x64u, // 'd' + E = 0x65u, // 'e' + F = 0x66u, // 'f' + G = 0x67u, // 'g' + H = 0x68u, // 'h' + I = 0x69u, // 'i' + J = 0x6Au, // 'j' + K = 0x6Bu, // 'k' + L = 0x6CU, // 'l' + M = 0x6DU, // 'm' + N = 0x6Eu, // 'n' + O = 0x6Fu, // 'o' + P = 0x70u, // 'p' + Q = 0x71u, // 'q' + R = 0x72u, // 'r' + S = 0x73u, // 's' + T = 0x74u, // 't' + U = 0x75u, // 'y' + V = 0x76u, // 'v' + W = 0x77u, // 'w' + X = 0x78u, // 'x' + Y = 0x79u, // 'y' + Z = 0x7Au, // 'z' + LeftBrace = 0x7BU, // '{' + Pipe = 0x7CU, // '|' + RightBrace = 0x7DU, // '}' + Tilde = 0x7Eu, // '~' + Delete = 0x7Fu, // '\x7F' + PlusMinus = 0xb1u, // '\xB1' - // Keys not producing a character - // Based on SDL Algo: ScanCode | 0x40000000 - CapsLock = 0x40000039u, - F1 = 0x4000003Au, - F2 = 0x4000003Bu, - F3 = 0x4000003CU, - F4 = 0x4000003DU, - F5 = 0x4000003Eu, - F6 = 0x4000003Fu, - F7 = 0x40000040u, - F8 = 0x40000041u, - F9 = 0x40000042u, - F10 = 0x40000043u, - F11 = 0x40000044u, - F12 = 0x40000045u, - PrintScreen = 0x40000046u, - ScrollLock = 0x40000047u, - Pause = 0x40000048u, - Insert = 0x40000049u, - Home = 0x4000004Au, - PageUp = 0x4000004Bu, - End = 0x4000004DU, - PageDown = 0x4000004Eu, - RightArrow = 0x4000004Fu, - LeftArrow = 0x40000050u, - DownArrow = 0x40000051u, - UpArrow = 0x40000052u, - NumlockClear = 0x40000053u, - KeyPad_Divide = 0x40000054u, - KeyPad_Multiply = 0x40000055u, - KeyPad_Minus = 0x40000056u, - KeyPad_Plus = 0x40000057u, - KeyPad_Enter = 0x40000058u, - KeyPad_Num1 = 0x40000059u, - KeyPad_Num2 = 0x4000005Au, - KeyPad_Num3 = 0x4000005Bu, - KeyPad_Num4 = 0x4000005Cu, - KeyPad_Num5 = 0x4000005Du, - KeyPad_Num6 = 0x4000005Eu, - KeyPad_Num7 = 0x4000005Fu, - KeyPad_Num8 = 0x40000060u, - KeyPad_Num9 = 0x40000061u, - KeyPad_Num0 = 0x40000062u, - KeyPad_Period = 0x40000063u, - Power = 0x40000066u, - KeyPad_Equals = 0x40000067u, - F13 = 0x40000068u, - F14 = 0x40000069u, - F15 = 0x4000006Au, - F16 = 0x4000006Bu, - F17 = 0x4000006Cu, - F18 = 0x4000006Du, - F19 = 0x4000006Eu, - F20 = 0x4000006Fu, - F21 = 0x40000070u, - F22 = 0x40000071u, - F23 = 0x40000072u, - F24 = 0x40000073u, - Mute = 0x4000007Fu, - VolumeUp = 0x40000080u, - VolumeDown = 0x40000081u, - KeyPad_Comma = 0x40000085u, - LeftControl = 0x400000E0u, - LeftShift = 0x400000E1u, - LeftAlt = 0x400000E2u, - LeftOSCommand = 0x400000E3u, - RightControl = 0x400000E4u, - RightShift = 0x400000E5u, - RightAlt = 0x400000E6u, - RightOSCommand = 0x400000E7u, - Sleep = 0x40000102u, - WakeUp = 0x40000103u, - Media_NextTrack = 0x4000010Bu, - Media_PreviousTrack = 0x4000010Cu, - Media_Stop = 0x4000010Du, - Media_Eject = 0x4000010Eu, - Media_PlayPause = 0x4000010Fu, - Media_Select = 0x40000110u, - }; + // Keys not producing a character + // Based on SDL Algo: ScanCode | 0x40000000 + CapsLock = 0x40000039u, + F1 = 0x4000003Au, + F2 = 0x4000003Bu, + F3 = 0x4000003CU, + F4 = 0x4000003DU, + F5 = 0x4000003Eu, + F6 = 0x4000003Fu, + F7 = 0x40000040u, + F8 = 0x40000041u, + F9 = 0x40000042u, + F10 = 0x40000043u, + F11 = 0x40000044u, + F12 = 0x40000045u, + PrintScreen = 0x40000046u, + ScrollLock = 0x40000047u, + Pause = 0x40000048u, + Insert = 0x40000049u, + Home = 0x4000004Au, + PageUp = 0x4000004Bu, + End = 0x4000004DU, + PageDown = 0x4000004Eu, + RightArrow = 0x4000004Fu, + LeftArrow = 0x40000050u, + DownArrow = 0x40000051u, + UpArrow = 0x40000052u, + NumlockClear = 0x40000053u, + KeyPad_Divide = 0x40000054u, + KeyPad_Multiply = 0x40000055u, + KeyPad_Minus = 0x40000056u, + KeyPad_Plus = 0x40000057u, + KeyPad_Enter = 0x40000058u, + KeyPad_Num1 = 0x40000059u, + KeyPad_Num2 = 0x4000005Au, + KeyPad_Num3 = 0x4000005Bu, + KeyPad_Num4 = 0x4000005Cu, + KeyPad_Num5 = 0x4000005Du, + KeyPad_Num6 = 0x4000005Eu, + KeyPad_Num7 = 0x4000005Fu, + KeyPad_Num8 = 0x40000060u, + KeyPad_Num9 = 0x40000061u, + KeyPad_Num0 = 0x40000062u, + KeyPad_Period = 0x40000063u, + Power = 0x40000066u, + KeyPad_Equals = 0x40000067u, + F13 = 0x40000068u, + F14 = 0x40000069u, + F15 = 0x4000006Au, + F16 = 0x4000006Bu, + F17 = 0x4000006Cu, + F18 = 0x4000006Du, + F19 = 0x4000006Eu, + F20 = 0x4000006Fu, + F21 = 0x40000070u, + F22 = 0x40000071u, + F23 = 0x40000072u, + F24 = 0x40000073u, + Mute = 0x4000007Fu, + VolumeUp = 0x40000080u, + VolumeDown = 0x40000081u, + KeyPad_Comma = 0x40000085u, + LeftControl = 0x400000E0u, + LeftShift = 0x400000E1u, + LeftAlt = 0x400000E2u, + LeftOSCommand = 0x400000E3u, + RightControl = 0x400000E4u, + RightShift = 0x400000E5u, + RightAlt = 0x400000E6u, + RightOSCommand = 0x400000E7u, + Sleep = 0x40000102u, + WakeUp = 0x40000103u, + Media_NextTrack = 0x4000010Bu, + Media_PreviousTrack = 0x4000010Cu, + Media_Stop = 0x4000010Du, + Media_Eject = 0x4000010Eu, + Media_PlayPause = 0x4000010Fu, + Media_Select = 0x40000110u, +}; - enum class KeyMod : uint16 - { - None = 0b0, - LeftShift = 0b0000'0000'0001u, - RightShift = 0b0000'0000'0010u, - LeftControl = 0b0000'0000'0100u, - RightControl = 0b0000'0000'1000u, - LeftAlt = 0b0000'0001'000u, - RightAlt = 0b0000'0010'0000u, - LeftOSCommand = 0b0000'0100'0000u, - RightOSCommand = 0b0000'1000'0000u, - NumLock = 0b0001'0000'0000u, - CapsLock = 0b0010'0000'0000u, - ScrollLock = 0b0100'0000'0000u, - Control = LeftControl | RightControl, - Shift = LeftShift | RightShift, - Alt = LeftAlt | RightAlt, - OSCommand = LeftOSCommand | RightOSCommand, - }; -} // namespace Juliet +enum class KeyMod : uint16 +{ + None = 0b0, + LeftShift = 0b0000'0000'0001u, + RightShift = 0b0000'0000'0010u, + LeftControl = 0b0000'0000'0100u, + RightControl = 0b0000'0000'1000u, + LeftAlt = 0b0000'0001'000u, + RightAlt = 0b0000'0010'0000u, + LeftOSCommand = 0b0000'0100'0000u, + RightOSCommand = 0b0000'1000'0000u, + NumLock = 0b0001'0000'0000u, + CapsLock = 0b0010'0000'0000u, + ScrollLock = 0b0100'0000'0000u, + Control = LeftControl | RightControl, + Shift = LeftShift | RightShift, + Alt = LeftAlt | RightAlt, + OSCommand = LeftOSCommand | RightOSCommand, +}; diff --git a/Juliet/include/Core/HAL/Keyboard/Keyboard.h b/Juliet/include/Core/HAL/Keyboard/Keyboard.h index e183b94..405b1d8 100644 --- a/Juliet/include/Core/HAL/Keyboard/Keyboard.h +++ b/Juliet/include/Core/HAL/Keyboard/Keyboard.h @@ -1,35 +1,32 @@ -#pragma once +#pragma once #include #include #include -namespace Juliet +using KeyboardID = uint8; + +enum class KeyPosition : bool { - using KeyboardID = uint8; + Up = false, + Down = true +}; - enum class KeyPosition : bool - { - Up = false, - Down = true - }; +struct KeyState +{ + KeyPosition Position; + float Time; +}; - struct KeyState - { - KeyPosition Position; - float Time; - }; +struct Key +{ + ScanCode ScanCode; + KeyCode KeyCode; + uint16 Raw; +}; - struct Key - { - ScanCode ScanCode; - KeyCode KeyCode; - uint16 Raw; - }; +extern JULIET_API bool IsKeyDown(ScanCode scanCode); +extern JULIET_API bool IsKeyPressed(ScanCode scanCode); - extern JULIET_API bool IsKeyDown(ScanCode scanCode); - extern JULIET_API bool IsKeyPressed(ScanCode scanCode); - - extern JULIET_API KeyMod GetKeyModState(); - extern JULIET_API KeyCode GetKeyCodeFromScanCode(ScanCode scanCode, KeyMod keyModState); -} // namespace Juliet +extern JULIET_API KeyMod GetKeyModState(); +extern JULIET_API KeyCode GetKeyCodeFromScanCode(ScanCode scanCode, KeyMod keyModState); diff --git a/Juliet/include/Core/HAL/Keyboard/ScanCode.h b/Juliet/include/Core/HAL/Keyboard/ScanCode.h index f45601f..8bf59fd 100644 --- a/Juliet/include/Core/HAL/Keyboard/ScanCode.h +++ b/Juliet/include/Core/HAL/Keyboard/ScanCode.h @@ -1,186 +1,183 @@ -#pragma once +#pragma once -namespace Juliet +// Follow the HID Usage page for USB +// https://usb.org/sites/default/files/hut1_5.pdf +// 0 to 256 Is dedicated to Keyboard Usage Page (0x07) +// 257 to 286 Is dedicated to Consumer Usage Page (0xC) +// 287 to 511 Is not implemented. Could be used for Mobile or Consoles +// ScanCode reprensent Physical Keys and Buttons +enum class ScanCode : uint16 { - // Follow the HID Usage page for USB - // https://usb.org/sites/default/files/hut1_5.pdf - // 0 to 256 Is dedicated to Keyboard Usage Page (0x07) - // 257 to 286 Is dedicated to Consumer Usage Page (0xC) - // 287 to 511 Is not implemented. Could be used for Mobile or Consoles - // ScanCode reprensent Physical Keys and Buttons - enum class ScanCode : uint16 - { - Unknown = 0, - Unsupported = 0, + Unknown = 0, + Unsupported = 0, - A = 4, - B = 5, - C = 6, - D = 7, - E = 8, - F = 9, - G = 10, - H = 11, - I = 12, - J = 13, - K = 14, - L = 15, - M = 16, - N = 17, - O = 18, - P = 19, - Q = 20, - R = 21, - S = 22, - T = 23, - U = 24, - V = 25, - W = 26, - X = 27, - Y = 28, - Z = 29, + A = 4, + B = 5, + C = 6, + D = 7, + E = 8, + F = 9, + G = 10, + H = 11, + I = 12, + J = 13, + K = 14, + L = 15, + M = 16, + N = 17, + O = 18, + P = 19, + Q = 20, + R = 21, + S = 22, + T = 23, + U = 24, + V = 25, + W = 26, + X = 27, + Y = 28, + Z = 29, - Num1 = 30, - Num2 = 31, - Num3 = 32, - Num4 = 33, - Num5 = 34, - Num6 = 35, - Num7 = 36, - Num8 = 37, - Num9 = 38, - Num0 = 39, + Num1 = 30, + Num2 = 31, + Num3 = 32, + Num4 = 33, + Num5 = 34, + Num6 = 35, + Num7 = 36, + Num8 = 37, + Num9 = 38, + Num0 = 39, - Return = 40, - Escape = 41, - Backspace = 42, - Tab = 43, - Space = 44, + Return = 40, + Escape = 41, + Backspace = 42, + Tab = 43, + Space = 44, - Minus = 45, - Equals = 46, - LeftBracket = 47, - RightBracket = 48, - Backslash = 49, - NonUSHash = 50, // Same as 49 but for ISO keyboards - Semicolon = 51, - Apostrophe = 52, - GraveAccent = 53, - Comma = 54, - Period = 55, - Slash = 56, - CapsLock = 57, + Minus = 45, + Equals = 46, + LeftBracket = 47, + RightBracket = 48, + Backslash = 49, + NonUSHash = 50, // Same as 49 but for ISO keyboards + Semicolon = 51, + Apostrophe = 52, + GraveAccent = 53, + Comma = 54, + Period = 55, + Slash = 56, + CapsLock = 57, - F1 = 58, - F2 = 59, - F3 = 60, - F4 = 61, - F5 = 62, - F6 = 63, - F7 = 64, - F8 = 65, - F9 = 66, - F10 = 67, - F11 = 68, - F12 = 69, + F1 = 58, + F2 = 59, + F3 = 60, + F4 = 61, + F5 = 62, + F6 = 63, + F7 = 64, + F8 = 65, + F9 = 66, + F10 = 67, + F11 = 68, + F12 = 69, - PrintScreen = 70, - ScrollLock = 71, - Pause = 72, - Insert = 73, + PrintScreen = 70, + ScrollLock = 71, + Pause = 72, + Insert = 73, - Home = 74, - PageUp = 75, - Delete = 76, - End = 77, - PageDown = 78, - RightArrow = 79, - LeftArrow = 80, - DownArrow = 81, - UpArrow = 82, + Home = 74, + PageUp = 75, + Delete = 76, + End = 77, + PageDown = 78, + RightArrow = 79, + LeftArrow = 80, + DownArrow = 81, + UpArrow = 82, - NumlockClear = 83, // Pc = Numlock / Mac = Clear + NumlockClear = 83, // Pc = Numlock / Mac = Clear - KeyPad_Divide = 84, - KeyPad_Multiply = 85, - KeyPad_Minus = 86, - KeyPad_Plus = 87, - KeyPad_Enter = 88, - KeyPad_Num1 = 89, - KeyPad_Num2 = 90, - KeyPad_Num3 = 91, - KeyPad_Num4 = 92, - KeyPad_Num5 = 93, - KeyPad_Num6 = 94, - KeyPad_Num7 = 95, - KeyPad_Num8 = 96, - KeyPad_Num9 = 97, - KeyPad_Num0 = 98, - KeyPad_Period = 99, + KeyPad_Divide = 84, + KeyPad_Multiply = 85, + KeyPad_Minus = 86, + KeyPad_Plus = 87, + KeyPad_Enter = 88, + KeyPad_Num1 = 89, + KeyPad_Num2 = 90, + KeyPad_Num3 = 91, + KeyPad_Num4 = 92, + KeyPad_Num5 = 93, + KeyPad_Num6 = 94, + KeyPad_Num7 = 95, + KeyPad_Num8 = 96, + KeyPad_Num9 = 97, + KeyPad_Num0 = 98, + KeyPad_Period = 99, - NonUSBackslash = 100, // ISO keyboards only - Power = 102, // Some mac have a Power key + NonUSBackslash = 100, // ISO keyboards only + Power = 102, // Some mac have a Power key - KeyPad_Equals = 103, - F13 = 104, - F14 = 105, - F15 = 106, - F16 = 107, - F17 = 108, - F18 = 109, - F19 = 110, - F20 = 111, - F21 = 112, - F22 = 113, - F23 = 114, - F24 = 115, + KeyPad_Equals = 103, + F13 = 104, + F14 = 105, + F15 = 106, + F16 = 107, + F17 = 108, + F18 = 109, + F19 = 110, + F20 = 111, + F21 = 112, + F22 = 113, + F23 = 114, + F24 = 115, - Mute = 127, - VolumeUp = 128, - VolumeDown = 129, + Mute = 127, + VolumeUp = 128, + VolumeDown = 129, - KeyPad_Comma = 133, + KeyPad_Comma = 133, - International1 = 135, // Mostly used on Asian keyboards - International2 = 136, - International3 = 137, // Yen Symbol - International4 = 138, - International5 = 139, - International6 = 140, - International7 = 141, - International8 = 142, - International9 = 143, - Lang1 = 144, // Hangul (Korean) - Lang2 = 145, // Hanja (Korean) - Lang3 = 146, // Katakana (Japanese) - Lang4 = 147, // Hiragana (Japanese) - Lang5 = 148, // Zenkaku/Hankaku (Japanese) - Lang6 = 149, // Unused - Lang7 = 150, // Unused - Lang8 = 151, // Unused - Lang9 = 152, // Unused + International1 = 135, // Mostly used on Asian keyboards + International2 = 136, + International3 = 137, // Yen Symbol + International4 = 138, + International5 = 139, + International6 = 140, + International7 = 141, + International8 = 142, + International9 = 143, + Lang1 = 144, // Hangul (Korean) + Lang2 = 145, // Hanja (Korean) + Lang3 = 146, // Katakana (Japanese) + Lang4 = 147, // Hiragana (Japanese) + Lang5 = 148, // Zenkaku/Hankaku (Japanese) + Lang6 = 149, // Unused + Lang7 = 150, // Unused + Lang8 = 151, // Unused + Lang9 = 152, // Unused - LeftControl = 224, - LeftShift = 225, - LeftAlt = 226, // Alt for PC, Option for Mac - LeftOSCommand = 227, // Window key for PC, Command for Mac - RightControl = 228, - RightShift = 229, - RightAlt = 230, // Alt Gr for PC, Option for Mac - RightOSCommand = 231, // Window key for PC, Command for Mac + LeftControl = 224, + LeftShift = 225, + LeftAlt = 226, // Alt for PC, Option for Mac + LeftOSCommand = 227, // Window key for PC, Command for Mac + RightControl = 228, + RightShift = 229, + RightAlt = 230, // Alt Gr for PC, Option for Mac + RightOSCommand = 231, // Window key for PC, Command for Mac - Sleep = 258, - WakeUp = 259, + Sleep = 258, + WakeUp = 259, - Media_NextTrack = 267, - Media_PreviousTrack = 268, - Media_Stop = 269, - Media_Eject = 270, - Media_PlayPause = 271, - Media_Select = 272, + Media_NextTrack = 267, + Media_PreviousTrack = 268, + Media_Stop = 269, + Media_Eject = 270, + Media_PlayPause = 271, + Media_Select = 272, - Reserved = 287, + Reserved = 287, - Count = 512 - }; -} // namespace Juliet + Count = 512 +}; diff --git a/Juliet/include/Core/HAL/Mouse/Mouse.h b/Juliet/include/Core/HAL/Mouse/Mouse.h index 9bd0f78..60438ff 100644 --- a/Juliet/include/Core/HAL/Mouse/Mouse.h +++ b/Juliet/include/Core/HAL/Mouse/Mouse.h @@ -1,28 +1,25 @@ -#pragma once +#pragma once -namespace Juliet +using MouseID = uint8; + +enum class MouseButton : uint8 { - using MouseID = uint8; + None = 0, + Left = 1 << 0, + Right = 1 << 1, + Middle = 1 << 2, + Button1 = 1 << 3, + Button2 = 1 << 4, +}; - enum class MouseButton : uint8 - { - None = 0, - Left = 1 << 0, - Right = 1 << 1, - Middle = 1 << 2, - Button1 = 1 << 3, - Button2 = 1 << 4, - }; +// TODO : Replace by Vector2f +struct MousePosition +{ + float X; + float Y; +}; - // TODO : Replace by Vector2f - struct MousePosition - { - float X; - float Y; - }; - - JULIET_API extern bool IsMouseButtonDown(MouseButton button); - JULIET_API extern MousePosition GetMousePosition(); - JULIET_API extern MousePosition GetMouseDelta(); - JULIET_API extern MouseButton GetMouseButtonState(); -} // namespace Juliet +JULIET_API extern bool IsMouseButtonDown(MouseButton button); +JULIET_API extern MousePosition GetMousePosition(); +JULIET_API extern MousePosition GetMouseDelta(); +JULIET_API extern MouseButton GetMouseButtonState(); diff --git a/Juliet/include/Core/HAL/OS/OS.h b/Juliet/include/Core/HAL/OS/OS.h index 5c0eff6..5d95468 100644 --- a/Juliet/include/Core/HAL/OS/OS.h +++ b/Juliet/include/Core/HAL/OS/OS.h @@ -1,49 +1,46 @@ -#pragma once +#pragma once #include #include -namespace Juliet +namespace Memory { - namespace Memory + Byte* OS_Reserve(size_t size); + bool OS_Commit(Byte* ptr, size_t size); + void OS_Release(Byte* ptr, size_t size); + + template + Type* OS_Reserve(size_t size) { - Byte* OS_Reserve(size_t size); - bool OS_Commit(Byte* ptr, size_t size); - void OS_Release(Byte* ptr, size_t size); + return reinterpret_cast(OS_Reserve(size)); + } - template - Type* OS_Reserve(size_t size) - { - return reinterpret_cast(OS_Reserve(size)); - } - - template - bool OS_Commit(Type* ptr, size_t size) - { - return OS_Commit(reinterpret_cast(ptr), size); - } - - template - void OS_Release(Type* ptr, size_t size) - { - OS_Release(reinterpret_cast(ptr), size); - } - - } // namespace Memory - - namespace Time + template + bool OS_Commit(Type* ptr, size_t size) { - uint64 Timestamp(); - void ComputeDeltaTime(); - float GetDeltaTime(); - uint64 GetFrameNumber(); - } // namespace Time + return OS_Commit(reinterpret_cast(ptr), size); + } - namespace Debug + template + void OS_Release(Type* ptr, size_t size) { - JULIET_API bool IsDebuggerPresent(); - } // namespace Debug + OS_Release(reinterpret_cast(ptr), size); + } - using EntryPointFunc = int (*)(int, wchar_t**); - JULIET_API int Bootstrap(EntryPointFunc entryPointFunc, int argc, wchar_t** argv); -} // namespace Juliet +} // namespace Memory + +namespace Time +{ + uint64 Timestamp(); + void ComputeDeltaTime(); + float GetDeltaTime(); + uint64 GetFrameNumber(); +} // namespace Time + +namespace Debug +{ + JULIET_API bool IsDebuggerPresent(); +} // namespace Debug + +using EntryPointFunc = int (*)(int, wchar_t**); +JULIET_API int Bootstrap(EntryPointFunc entryPointFunc, int argc, wchar_t** argv); diff --git a/Juliet/include/Core/HotReload/HotReload.h b/Juliet/include/Core/HotReload/HotReload.h index 8aa724d..c5de9c5 100644 --- a/Juliet/include/Core/HotReload/HotReload.h +++ b/Juliet/include/Core/HotReload/HotReload.h @@ -1,38 +1,35 @@ -#pragma once +#pragma once #include -namespace Juliet +// Fwd Declare +struct DynamicLibrary; + +struct HotReloadCode { - // Fwd Declare - struct DynamicLibrary; + String DLLFullPath; + String LockFullPath; + String TransientDLLName; - struct HotReloadCode - { - String DLLFullPath; - String LockFullPath; - String TransientDLLName; + uint64 LastWriteTime; - uint64 LastWriteTime; + DynamicLibrary* Dll; - DynamicLibrary* Dll; + void** Functions; + const char** FunctionNames; + uint32 FunctionCount; - void** Functions; - const char** FunctionNames; - uint32 FunctionCount; + uint32 UniqueID; - uint32 UniqueID; + bool IsValid : 1; +}; - bool IsValid : 1; - }; +extern JULIET_API void InitHotReloadCode(NonNullPtr arena, HotReloadCode& code, String dllName, + String transientDllName, String lockFilename); +extern JULIET_API void ShutdownHotReloadCode(HotReloadCode& code); - extern JULIET_API void InitHotReloadCode(NonNullPtr arena, HotReloadCode& code, String dllName, - String transientDllName, String lockFilename); - extern JULIET_API void ShutdownHotReloadCode(HotReloadCode& code); +extern JULIET_API void LoadCode(HotReloadCode& code); +extern JULIET_API void UnloadCode(HotReloadCode& code); - extern JULIET_API void LoadCode(HotReloadCode& code); - extern JULIET_API void UnloadCode(HotReloadCode& code); - - extern JULIET_API void ReloadCode(HotReloadCode& code); - extern JULIET_API bool ShouldReloadCode(const HotReloadCode& code); -} // namespace Juliet +extern JULIET_API void ReloadCode(HotReloadCode& code); +extern JULIET_API bool ShouldReloadCode(const HotReloadCode& code); diff --git a/Juliet/include/Core/ImGui/ImGuiService.h b/Juliet/include/Core/ImGui/ImGuiService.h index 3a5509c..4182d6d 100644 --- a/Juliet/include/Core/ImGui/ImGuiService.h +++ b/Juliet/include/Core/ImGui/ImGuiService.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -7,25 +7,22 @@ struct ImGuiContext; -namespace Juliet +struct Window; +struct GraphicsDevice; + +namespace ImGuiService { - struct Window; - struct GraphicsDevice; + JULIET_API void Initialize(NonNullPtr window); + JULIET_API void Shutdown(); - namespace ImGuiService - { - JULIET_API void Initialize(NonNullPtr window); - JULIET_API void Shutdown(); + JULIET_API void NewFrame(); + JULIET_API void Render(); - JULIET_API void NewFrame(); - JULIET_API void Render(); + JULIET_API bool IsInitialized(); + JULIET_API ImGuiContext* GetContext(); - JULIET_API bool IsInitialized(); - JULIET_API ImGuiContext* GetContext(); - - // Run internal unit tests - JULIET_API void RunTests(); - } // namespace ImGuiService -} // namespace Juliet + // Run internal unit tests + JULIET_API void RunTests(); +} // namespace ImGuiService #endif // JULIET_ENABLE_IMGUI diff --git a/Juliet/include/Core/ImGui/ImGuiTests.h b/Juliet/include/Core/ImGui/ImGuiTests.h index 59befec..f926b08 100644 --- a/Juliet/include/Core/ImGui/ImGuiTests.h +++ b/Juliet/include/Core/ImGui/ImGuiTests.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -6,7 +6,7 @@ #include -namespace Juliet::UnitTest +namespace UnitTest { void TestImGui(); } diff --git a/Juliet/include/Core/JulietInit.h b/Juliet/include/Core/JulietInit.h index 01e935a..c052856 100644 --- a/Juliet/include/Core/JulietInit.h +++ b/Juliet/include/Core/JulietInit.h @@ -1,26 +1,23 @@ -#pragma once +#pragma once #include -namespace Juliet +enum class JulietInit_Flags : uint8 { - enum class JulietInit_Flags : uint8 - { - None = 0, - Display = 1 << 0, - Audio = 1 << 1, - Count = Audio, - All = 0xFb - }; + None = 0, + Display = 1 << 0, + Audio = 1 << 1, + Count = Audio, + All = 0xFb +}; - struct Arena; +struct Arena; - struct GameData - { - struct GameState* GameState; - Arena* ScratchArena; - }; +struct GameData +{ + struct GameState* GameState; + Arena* ScratchArena; +}; - void JulietInit(JulietInit_Flags flags); - void JulietShutdown(); -} // namespace Juliet +void JulietInit(JulietInit_Flags flags); +void JulietShutdown(); diff --git a/Juliet/include/Core/Logging/LogManager.h b/Juliet/include/Core/Logging/LogManager.h index cd5bd73..32acff0 100644 --- a/Juliet/include/Core/Logging/LogManager.h +++ b/Juliet/include/Core/Logging/LogManager.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -9,21 +9,18 @@ // TODO Juliet Containers + Allocators... // TODO: Juliet chrono, because it prevents me from doing #define global static -namespace Juliet -{ - enum class LogLevel : uint8; - enum class LogCategory : uint8; +enum class LogLevel : uint8; +enum class LogCategory : uint8; - extern void JULIET_API InitializeLogManager(); - extern void JULIET_API ShutdownLogManager(); +extern void JULIET_API InitializeLogManager(); +extern void JULIET_API ShutdownLogManager(); - extern void JULIET_API LogScopeBegin(); - // TODO everything that happened in there to export them to file or something - extern void JULIET_API LogScopeEnd(); +extern void JULIET_API LogScopeBegin(); +// TODO everything that happened in there to export them to file or something +extern void JULIET_API LogScopeEnd(); - extern void JULIET_API Log(LogLevel level, LogCategory category, const char* fmt, ...); - extern void JULIET_API LogDebug(LogCategory category, const char* fmt, ...); - extern void JULIET_API LogMessage(LogCategory category, const char* fmt, ...); - extern void JULIET_API LogWarning(LogCategory category, const char* fmt, ...); - extern void JULIET_API LogError(LogCategory category, const char* fmt, ...); -} // namespace Juliet +extern void JULIET_API Log(LogLevel level, LogCategory category, const char* fmt, ...); +extern void JULIET_API LogDebug(LogCategory category, const char* fmt, ...); +extern void JULIET_API LogMessage(LogCategory category, const char* fmt, ...); +extern void JULIET_API LogWarning(LogCategory category, const char* fmt, ...); +extern void JULIET_API LogError(LogCategory category, const char* fmt, ...); diff --git a/Juliet/include/Core/Logging/LogTypes.h b/Juliet/include/Core/Logging/LogTypes.h index 187b2f0..42eab4d 100644 --- a/Juliet/include/Core/Logging/LogTypes.h +++ b/Juliet/include/Core/Logging/LogTypes.h @@ -1,22 +1,19 @@ -#pragma once +#pragma once -namespace Juliet +enum class LogLevel : uint8 { - enum class LogLevel : uint8 - { - Debug = 0, - Message = 1, - Warning = 2, - Error = 3, - }; + Debug = 0, + Message = 1, + Warning = 2, + Error = 3, +}; - enum class LogCategory : uint8 - { - Core = 0, - Graphics = 1, - Networking = 2, - Engine = 3, - Tool = 4, - Game = 5, - }; -} // namespace Juliet +enum class LogCategory : uint8 +{ + Core = 0, + Graphics = 1, + Networking = 2, + Engine = 3, + Tool = 4, + Game = 5, +}; diff --git a/Juliet/include/Core/Main.h b/Juliet/include/Core/Main.h index 7bf98ce..174fc4b 100644 --- a/Juliet/include/Core/Main.h +++ b/Juliet/include/Core/Main.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include @@ -12,12 +12,12 @@ extern int JulietMain(int, wchar_t**); #if UNICODE int wmain(int argc, wchar_t** argv) { - return Juliet::Bootstrap(JulietMain, argc, argv); + return Bootstrap(JulietMain, argc, argv); } #else int main(int argc, char** argv) { - return Juliet::Bootstrap(JulietMain, argc, argv); + return Bootstrap(JulietMain, argc, argv); } #endif @@ -38,7 +38,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) (void)szCmdLine; (void)sw; - return Juliet::Bootstrap(JulietMain, __argc, __wargv); + return Bootstrap(JulietMain, __argc, __wargv); } } #else diff --git a/Juliet/include/Core/Math/MathUtils.h b/Juliet/include/Core/Math/MathUtils.h index f7b6aff..97e910c 100644 --- a/Juliet/include/Core/Math/MathUtils.h +++ b/Juliet/include/Core/Math/MathUtils.h @@ -1,52 +1,49 @@ -#pragma once +#pragma once #include #include -namespace Juliet +extern JULIET_API float RoundF(float value); + +inline int32 LRoundF(float value) { - extern JULIET_API float RoundF(float value); + return static_cast(RoundF(value)); +} - inline int32 LRoundF(float value) - { - return static_cast(RoundF(value)); - } +template +constexpr Type Min(Type lhs, Type rhs) +{ + return rhs < lhs ? rhs : lhs; +} - template - constexpr Type Min(Type lhs, Type rhs) - { - return rhs < lhs ? rhs : lhs; - } +template +constexpr Type Max(Type lhs, Type rhs) +{ + return lhs < rhs ? rhs : lhs; +} - template - constexpr Type Max(Type lhs, Type rhs) - { - return lhs < rhs ? rhs : lhs; - } +template +constexpr Type ClampTop(Type value, Type X) +{ + return Min(value, X); +} - template - constexpr Type ClampTop(Type value, Type X) - { - return Min(value, X); - } +template +constexpr Type ClampBottom(Type value, Type X) +{ + return Max(value, X); +} - template - constexpr Type ClampBottom(Type value, Type X) +template +constexpr Type Clamp(Type val, Type min, Type max) +{ + if (val < min) { - return Max(value, X); + return min; } - - template - constexpr Type Clamp(Type val, Type min, Type max) + if (val > max) { - if (val < min) - { - return min; - } - if (val > max) - { - return max; - } - return val; + return max; } -} // namespace Juliet + return val; +} diff --git a/Juliet/include/Core/Math/Matrix.h b/Juliet/include/Core/Math/Matrix.h index 79f3d85..f824893 100644 --- a/Juliet/include/Core/Math/Matrix.h +++ b/Juliet/include/Core/Math/Matrix.h @@ -1,194 +1,191 @@ -#pragma once +#pragma once #include #include -namespace Juliet +struct Matrix { - struct Matrix - { - float m[4][4]; - }; + float m[4][4]; +}; - [[nodiscard]] inline Matrix MatrixIdentity() - { - Matrix result = {}; - result.m[0][0] = 1.0f; - result.m[1][1] = 1.0f; - result.m[2][2] = 1.0f; - result.m[3][3] = 1.0f; - return result; - } +[[nodiscard]] inline Matrix MatrixIdentity() +{ + Matrix result = {}; + result.m[0][0] = 1.0f; + result.m[1][1] = 1.0f; + result.m[2][2] = 1.0f; + result.m[3][3] = 1.0f; + return result; +} - [[nodiscard]] inline Matrix operator*(const Matrix& lhs, const Matrix& rhs) +[[nodiscard]] inline Matrix operator*(const Matrix& lhs, const Matrix& rhs) +{ + Matrix result = {}; + for (int i = 0; i < 4; ++i) { - Matrix result = {}; - for (int i = 0; i < 4; ++i) + for (int j = 0; j < 4; ++j) { - for (int j = 0; j < 4; ++j) + for (int k = 0; k < 4; ++k) { - for (int k = 0; k < 4; ++k) - { - result.m[i][j] += lhs.m[i][k] * rhs.m[k][j]; - } + result.m[i][j] += lhs.m[i][k] * rhs.m[k][j]; } } - return result; } + return result; +} - [[nodiscard]] inline Matrix MatrixTranslation(float x, float y, float z) +[[nodiscard]] inline Matrix MatrixTranslation(float x, float y, float z) +{ + Matrix result = MatrixIdentity(); + result.m[0][3] = x; + result.m[1][3] = y; + result.m[2][3] = z; + return result; +} + +[[nodiscard]] inline Matrix MatrixScale(float x, float y, float z) +{ + Matrix result = MatrixIdentity(); + result.m[0][0] = x; + result.m[1][1] = y; + result.m[2][2] = z; + return result; +} + +[[nodiscard]] inline Matrix MatrixRotationX(float radians) +{ + float c = cosf(radians); + float s = sinf(radians); + Matrix result = MatrixIdentity(); + result.m[1][1] = c; + result.m[1][2] = -s; + result.m[2][1] = s; + result.m[2][2] = c; + return result; +} + +[[nodiscard]] inline Matrix MatrixRotationY(float radians) +{ + float c = cosf(radians); + float s = sinf(radians); + Matrix result = MatrixIdentity(); + result.m[0][0] = c; + result.m[0][2] = s; + result.m[2][0] = -s; + result.m[2][2] = c; + return result; +} + +[[nodiscard]] inline Matrix MatrixRotationZ(float radians) +{ + float c = cosf(radians); + float s = sinf(radians); + Matrix result = MatrixIdentity(); + result.m[0][0] = c; + result.m[0][1] = -s; + result.m[1][0] = s; + result.m[1][1] = c; + return result; +} + +inline void MatrixTranslate(Matrix& m, const Vector3& v) +{ + m.m[0][3] += v.x; + m.m[1][3] += v.y; + m.m[2][3] += v.z; +} + +[[nodiscard]] inline Matrix MatrixRotation(float x, float y, float z) +{ + return MatrixRotationX(x) * MatrixRotationY(y) * MatrixRotationZ(z); +} + +inline Matrix LookAt(const Vector3& eye, const Vector3& target, const Vector3& up) +{ + // Left-Handed convention + Vector3 zaxis = Normalize(target - eye); // Forward is +z + Vector3 xaxis = Normalize(Cross(up, zaxis)); + Vector3 yaxis = Cross(zaxis, xaxis); + + Matrix result = {}; + // Row 0 + result.m[0][0] = xaxis.x; + result.m[0][1] = xaxis.y; + result.m[0][2] = xaxis.z; + result.m[0][3] = -Dot(xaxis, eye); + + // Row 1 + result.m[1][0] = yaxis.x; + result.m[1][1] = yaxis.y; + result.m[1][2] = yaxis.z; + result.m[1][3] = -Dot(yaxis, eye); + + // Row 2 + result.m[2][0] = zaxis.x; + result.m[2][1] = zaxis.y; + result.m[2][2] = zaxis.z; + result.m[2][3] = -Dot(zaxis, eye); + + // Row 3 + result.m[3][3] = 1.0f; + + return result; +} + +inline Matrix PerspectiveFov(float fovY, float aspectRatio, float nearZ, float farZ) +{ + // Left-Handed Perspective + float yScale = 1.0f / tanf(fovY * 0.5f); + float xScale = yScale / aspectRatio; + + Matrix result = {}; + result.m[0][0] = xScale; + result.m[1][1] = yScale; + result.m[2][2] = farZ / (farZ - nearZ); + result.m[2][3] = (-nearZ * farZ) / (farZ - nearZ); + result.m[3][2] = 1.0f; + result.m[3][3] = 0.0f; + return result; +} + +[[nodiscard]] inline Matrix MatrixInverse(const Matrix& m) +{ + Matrix out = {}; + + float m00 = m.m[0][0], m01 = m.m[0][1], m02 = m.m[0][2], m03 = m.m[0][3]; + float m10 = m.m[1][0], m11 = m.m[1][1], m12 = m.m[1][2], m13 = m.m[1][3]; + float m20 = m.m[2][0], m21 = m.m[2][1], m22 = m.m[2][2], m23 = m.m[2][3]; + float m30 = m.m[3][0], m31 = m.m[3][1], m32 = m.m[3][2], m33 = m.m[3][3]; + + out.m[0][0] = m11 * m22 * m33 - m11 * m23 * m32 - m21 * m12 * m33 + m21 * m13 * m32 + m31 * m12 * m23 - m31 * m13 * m22; + out.m[1][0] = -m10 * m22 * m33 + m10 * m23 * m32 + m20 * m12 * m33 - m20 * m13 * m32 - m30 * m12 * m23 + m30 * m13 * m22; + out.m[2][0] = m10 * m21 * m33 - m10 * m23 * m31 - m20 * m11 * m33 + m20 * m13 * m31 + m30 * m11 * m23 - m30 * m13 * m21; + out.m[3][0] = -m10 * m21 * m32 + m10 * m22 * m31 + m20 * m11 * m32 - m20 * m12 * m31 - m30 * m11 * m22 + m30 * m12 * m21; + + out.m[0][1] = -m01 * m22 * m33 + m01 * m23 * m32 + m21 * m02 * m33 - m21 * m03 * m32 - m31 * m02 * m23 + m31 * m03 * m22; + out.m[1][1] = m00 * m22 * m33 - m00 * m23 * m32 - m20 * m02 * m33 + m20 * m03 * m32 + m30 * m02 * m23 - m30 * m03 * m22; + out.m[2][1] = -m00 * m21 * m33 + m00 * m23 * m31 + m20 * m01 * m33 - m20 * m03 * m31 - m30 * m01 * m23 + m30 * m03 * m21; + out.m[3][1] = m00 * m21 * m32 - m00 * m22 * m31 - m20 * m01 * m32 + m20 * m02 * m31 + m30 * m01 * m22 - m30 * m02 * m21; + + out.m[0][2] = m01 * m12 * m33 - m01 * m13 * m32 - m11 * m02 * m33 + m11 * m03 * m32 + m31 * m02 * m13 - m31 * m03 * m12; + out.m[1][2] = -m00 * m12 * m33 + m00 * m13 * m32 + m10 * m02 * m33 - m10 * m03 * m32 - m30 * m02 * m13 + m30 * m03 * m12; + out.m[2][2] = m00 * m11 * m33 - m00 * m13 * m31 - m10 * m01 * m33 + m10 * m03 * m31 + m30 * m01 * m13 - m30 * m03 * m11; + out.m[3][2] = -m00 * m11 * m32 + m00 * m12 * m31 + m10 * m01 * m32 - m10 * m02 * m31 - m30 * m01 * m12 + m30 * m02 * m11; + + out.m[0][3] = -m01 * m12 * m23 + m01 * m13 * m22 + m11 * m02 * m23 - m11 * m03 * m22 - m21 * m02 * m13 + m21 * m03 * m12; + out.m[1][3] = m00 * m12 * m23 - m00 * m13 * m22 - m10 * m02 * m23 + m10 * m03 * m22 + m20 * m02 * m13 - m20 * m03 * m12; + out.m[2][3] = -m00 * m11 * m23 + m00 * m13 * m21 + m10 * m01 * m23 - m10 * m03 * m21 - m20 * m01 * m13 + m20 * m03 * m11; + out.m[3][3] = m00 * m11 * m22 - m00 * m12 * m21 - m10 * m01 * m22 + m10 * m02 * m21 + m20 * m01 * m12 - m20 * m02 * m11; + + float det = m00 * out.m[0][0] + m01 * out.m[1][0] + m02 * out.m[2][0] + m03 * out.m[3][0]; + + if (det != 0.0f) { - Matrix result = MatrixIdentity(); - result.m[0][3] = x; - result.m[1][3] = y; - result.m[2][3] = z; - return result; + float invDet = 1.0f / det; + for (int r = 0; r < 4; ++r) + for (int c = 0; c < 4; ++c) + out.m[r][c] *= invDet; } - [[nodiscard]] inline Matrix MatrixScale(float x, float y, float z) - { - Matrix result = MatrixIdentity(); - result.m[0][0] = x; - result.m[1][1] = y; - result.m[2][2] = z; - return result; - } - - [[nodiscard]] inline Matrix MatrixRotationX(float radians) - { - float c = cosf(radians); - float s = sinf(radians); - Matrix result = MatrixIdentity(); - result.m[1][1] = c; - result.m[1][2] = -s; - result.m[2][1] = s; - result.m[2][2] = c; - return result; - } - - [[nodiscard]] inline Matrix MatrixRotationY(float radians) - { - float c = cosf(radians); - float s = sinf(radians); - Matrix result = MatrixIdentity(); - result.m[0][0] = c; - result.m[0][2] = s; - result.m[2][0] = -s; - result.m[2][2] = c; - return result; - } - - [[nodiscard]] inline Matrix MatrixRotationZ(float radians) - { - float c = cosf(radians); - float s = sinf(radians); - Matrix result = MatrixIdentity(); - result.m[0][0] = c; - result.m[0][1] = -s; - result.m[1][0] = s; - result.m[1][1] = c; - return result; - } - - inline void MatrixTranslate(Matrix& m, const Vector3& v) - { - m.m[0][3] += v.x; - m.m[1][3] += v.y; - m.m[2][3] += v.z; - } - - [[nodiscard]] inline Matrix MatrixRotation(float x, float y, float z) - { - return MatrixRotationX(x) * MatrixRotationY(y) * MatrixRotationZ(z); - } - - inline Matrix LookAt(const Vector3& eye, const Vector3& target, const Vector3& up) - { - // Left-Handed convention - Vector3 zaxis = Normalize(target - eye); // Forward is +z - Vector3 xaxis = Normalize(Cross(up, zaxis)); - Vector3 yaxis = Cross(zaxis, xaxis); - - Matrix result = {}; - // Row 0 - result.m[0][0] = xaxis.x; - result.m[0][1] = xaxis.y; - result.m[0][2] = xaxis.z; - result.m[0][3] = -Dot(xaxis, eye); - - // Row 1 - result.m[1][0] = yaxis.x; - result.m[1][1] = yaxis.y; - result.m[1][2] = yaxis.z; - result.m[1][3] = -Dot(yaxis, eye); - - // Row 2 - result.m[2][0] = zaxis.x; - result.m[2][1] = zaxis.y; - result.m[2][2] = zaxis.z; - result.m[2][3] = -Dot(zaxis, eye); - - // Row 3 - result.m[3][3] = 1.0f; - - return result; - } - - inline Matrix PerspectiveFov(float fovY, float aspectRatio, float nearZ, float farZ) - { - // Left-Handed Perspective - float yScale = 1.0f / tanf(fovY * 0.5f); - float xScale = yScale / aspectRatio; - - Matrix result = {}; - result.m[0][0] = xScale; - result.m[1][1] = yScale; - result.m[2][2] = farZ / (farZ - nearZ); - result.m[2][3] = (-nearZ * farZ) / (farZ - nearZ); - result.m[3][2] = 1.0f; - result.m[3][3] = 0.0f; - return result; - } - - [[nodiscard]] inline Matrix MatrixInverse(const Matrix& m) - { - Matrix out = {}; - - float m00 = m.m[0][0], m01 = m.m[0][1], m02 = m.m[0][2], m03 = m.m[0][3]; - float m10 = m.m[1][0], m11 = m.m[1][1], m12 = m.m[1][2], m13 = m.m[1][3]; - float m20 = m.m[2][0], m21 = m.m[2][1], m22 = m.m[2][2], m23 = m.m[2][3]; - float m30 = m.m[3][0], m31 = m.m[3][1], m32 = m.m[3][2], m33 = m.m[3][3]; - - out.m[0][0] = m11 * m22 * m33 - m11 * m23 * m32 - m21 * m12 * m33 + m21 * m13 * m32 + m31 * m12 * m23 - m31 * m13 * m22; - out.m[1][0] = -m10 * m22 * m33 + m10 * m23 * m32 + m20 * m12 * m33 - m20 * m13 * m32 - m30 * m12 * m23 + m30 * m13 * m22; - out.m[2][0] = m10 * m21 * m33 - m10 * m23 * m31 - m20 * m11 * m33 + m20 * m13 * m31 + m30 * m11 * m23 - m30 * m13 * m21; - out.m[3][0] = -m10 * m21 * m32 + m10 * m22 * m31 + m20 * m11 * m32 - m20 * m12 * m31 - m30 * m11 * m22 + m30 * m12 * m21; - - out.m[0][1] = -m01 * m22 * m33 + m01 * m23 * m32 + m21 * m02 * m33 - m21 * m03 * m32 - m31 * m02 * m23 + m31 * m03 * m22; - out.m[1][1] = m00 * m22 * m33 - m00 * m23 * m32 - m20 * m02 * m33 + m20 * m03 * m32 + m30 * m02 * m23 - m30 * m03 * m22; - out.m[2][1] = -m00 * m21 * m33 + m00 * m23 * m31 + m20 * m01 * m33 - m20 * m03 * m31 - m30 * m01 * m23 + m30 * m03 * m21; - out.m[3][1] = m00 * m21 * m32 - m00 * m22 * m31 - m20 * m01 * m32 + m20 * m02 * m31 + m30 * m01 * m22 - m30 * m02 * m21; - - out.m[0][2] = m01 * m12 * m33 - m01 * m13 * m32 - m11 * m02 * m33 + m11 * m03 * m32 + m31 * m02 * m13 - m31 * m03 * m12; - out.m[1][2] = -m00 * m12 * m33 + m00 * m13 * m32 + m10 * m02 * m33 - m10 * m03 * m32 - m30 * m02 * m13 + m30 * m03 * m12; - out.m[2][2] = m00 * m11 * m33 - m00 * m13 * m31 - m10 * m01 * m33 + m10 * m03 * m31 + m30 * m01 * m13 - m30 * m03 * m11; - out.m[3][2] = -m00 * m11 * m32 + m00 * m12 * m31 + m10 * m01 * m32 - m10 * m02 * m31 - m30 * m01 * m12 + m30 * m02 * m11; - - out.m[0][3] = -m01 * m12 * m23 + m01 * m13 * m22 + m11 * m02 * m23 - m11 * m03 * m22 - m21 * m02 * m13 + m21 * m03 * m12; - out.m[1][3] = m00 * m12 * m23 - m00 * m13 * m22 - m10 * m02 * m23 + m10 * m03 * m22 + m20 * m02 * m13 - m20 * m03 * m12; - out.m[2][3] = -m00 * m11 * m23 + m00 * m13 * m21 + m10 * m01 * m23 - m10 * m03 * m21 - m20 * m01 * m13 + m20 * m03 * m11; - out.m[3][3] = m00 * m11 * m22 - m00 * m12 * m21 - m10 * m01 * m22 + m10 * m02 * m21 + m20 * m01 * m12 - m20 * m02 * m11; - - float det = m00 * out.m[0][0] + m01 * out.m[1][0] + m02 * out.m[2][0] + m03 * out.m[3][0]; - - if (det != 0.0f) - { - float invDet = 1.0f / det; - for (int r = 0; r < 4; ++r) - for (int c = 0; c < 4; ++c) - out.m[r][c] *= invDet; - } - - return out; - } -} // namespace Juliet + return out; +} diff --git a/Juliet/include/Core/Math/Shape.h b/Juliet/include/Core/Math/Shape.h index 39044b9..f692383 100644 --- a/Juliet/include/Core/Math/Shape.h +++ b/Juliet/include/Core/Math/Shape.h @@ -1,12 +1,9 @@ -#pragma once +#pragma once -namespace Juliet +struct Rectangle { - struct Rectangle - { - int32 X; - int32 Y; - int32 Width; - int32 Height; - }; -} // namespace Juliet + int32 X; + int32 Y; + int32 Width; + int32 Height; +}; diff --git a/Juliet/include/Core/Math/Vector.h b/Juliet/include/Core/Math/Vector.h index 5158d74..3d089ad 100644 --- a/Juliet/include/Core/Math/Vector.h +++ b/Juliet/include/Core/Math/Vector.h @@ -1,39 +1,36 @@ -#pragma once +#pragma once #include #include #include -namespace Juliet +struct Vector3 { - struct Vector3 - { - float x, y, z; + float x, y, z; - Vector3 operator+(const Vector3& rhs) const { return { x + rhs.x, y + rhs.y, z + rhs.z }; } - Vector3 operator-(const Vector3& rhs) const { return { x - rhs.x, y - rhs.y, z - rhs.z }; } - Vector3 operator*(float s) const { return { x * s, y * s, z * s }; } - }; + Vector3 operator+(const Vector3& rhs) const { return { x + rhs.x, y + rhs.y, z + rhs.z }; } + Vector3 operator-(const Vector3& rhs) const { return { x - rhs.x, y - rhs.y, z - rhs.z }; } + Vector3 operator*(float s) const { return { x * s, y * s, z * s }; } +}; - struct Vector4 - { - float x, y, z, w; - }; +struct Vector4 +{ + float x, y, z, w; +}; - inline Vector3 Normalize(const Vector3& v) +inline Vector3 Normalize(const Vector3& v) +{ + float len = sqrtf(v.x * v.x + v.y * v.y + v.z * v.z); + if (len > 0.0001f) { - float len = sqrtf(v.x * v.x + v.y * v.y + v.z * v.z); - if (len > 0.0001f) - { - return { v.x / len, v.y / len, v.z / len }; - } - return v; + return { v.x / len, v.y / len, v.z / len }; } + return v; +} - inline Vector3 Cross(const Vector3& a, const Vector3& b) - { - return { a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x }; - } +inline Vector3 Cross(const Vector3& a, const Vector3& b) +{ + return { a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x }; +} - inline float Dot(const Vector3& a, const Vector3& b) { return a.x * b.x + a.y * b.y + a.z * b.z; } -} // namespace Juliet +inline float Dot(const Vector3& a, const Vector3& b) { return a.x * b.x + a.y * b.y + a.z * b.z; } diff --git a/Juliet/include/Core/Memory/Allocator.h b/Juliet/include/Core/Memory/Allocator.h index 621bca9..e144783 100644 --- a/Juliet/include/Core/Memory/Allocator.h +++ b/Juliet/include/Core/Memory/Allocator.h @@ -1,31 +1,28 @@ -#pragma once +#pragma once #include #include -namespace Juliet -{ - // Uninitialized allocation - JULIET_API void* Malloc(size_t elem_size); - // Initialized to 0 allocation - JULIET_API void* Calloc(size_t nb_elem, size_t elem_size); - JULIET_API void* Realloc(void* memory, size_t newSize); +// Uninitialized allocation +JULIET_API void* Malloc(size_t elem_size); +// Initialized to 0 allocation +JULIET_API void* Calloc(size_t nb_elem, size_t elem_size); +JULIET_API void* Realloc(void* memory, size_t newSize); - // Free - template - void Free(Type* memory) +// Free +template +void Free(Type* memory) +{ + Assert(memory); + ::free(memory); +} +// Free and Set the ptr to nullptr +template +void SafeFree(Type*& memory) +{ + if (memory) { - Assert(memory); ::free(memory); + memory = nullptr; } - // Free and Set the ptr to nullptr - template - void SafeFree(Type*& memory) - { - if (memory) - { - ::free(memory); - memory = nullptr; - } - } -} // namespace Juliet +} diff --git a/Juliet/include/Core/Memory/MemoryArena.h b/Juliet/include/Core/Memory/MemoryArena.h index da644c9..113d6ce 100644 --- a/Juliet/include/Core/Memory/MemoryArena.h +++ b/Juliet/include/Core/Memory/MemoryArena.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -10,122 +10,119 @@ #include #endif -namespace Juliet +constexpr global uint64 g_Arena_Default_Reserve_Size = Megabytes(64); +constexpr global uint64 g_Arena_Default_Commit_Size = Kilobytes(64); +constexpr global uint64 k_ArenaHeaderSize = 128; + +#if JULIET_DEBUG +struct ArenaDebugInfo; +JULIET_API String FormatDebugTagV(const char* formatStr, std::format_args args); +#endif + +struct Arena { - constexpr global uint64 g_Arena_Default_Reserve_Size = Megabytes(64); - constexpr global uint64 g_Arena_Default_Commit_Size = Kilobytes(64); - constexpr global uint64 k_ArenaHeaderSize = 128; + Arena* Previous; + Arena* Current; + + uint64 BasePosition; + uint64 Position; + uint64 Alignment; + + uint64 CommitSize; + uint64 ReserveSize; + + uint64 Committed; + uint64 Reserved; + + Arena* FreeBlockLast; + + JULIET_DEBUG_ONLY(uint16 LostNodeCount;) + JULIET_DEBUG_ONLY(bool CanReserveMore : 1;) + + JULIET_DEBUG_ONLY(Arena* GlobalNext;) + JULIET_DEBUG_ONLY(Arena* GlobalPrev;) + JULIET_DEBUG_ONLY(ArenaDebugInfo* FirstDebugInfo;) + const char* Name; +}; +static_assert(sizeof(Arena) <= k_ArenaHeaderSize); + +struct TempArena +{ + Arena* Arena; + index_t Position; +}; + +struct ArenaParams +{ + uint64 ReserveSize = g_Arena_Default_Reserve_Size; + uint64 CommitSize = g_Arena_Default_Commit_Size; + + const char* Name; + + // When false, will assert if a new block is reserved. + JULIET_DEBUG_ONLY(bool CanReserveMore : 1 = true;) +}; + +[[nodiscard]] JULIET_API Arena* ArenaAllocate(const ArenaParams& params, + const std::source_location& loc = std::source_location::current()); +JULIET_API void ArenaRelease(NonNullPtr arena); + +// Raw Push, can be used but templated helpers exists below +[[nodiscard]] JULIET_API void* ArenaPush(NonNullPtr arena, size_t size, size_t align, + bool shouldBeZeroed JULIET_DEBUG_PARAM(const char* tag)); +JULIET_API void ArenaPopTo(NonNullPtr arena, size_t position); +JULIET_API void ArenaPop(NonNullPtr arena, size_t amount); +JULIET_API void ArenaClear(NonNullPtr arena); +[[nodiscard]] JULIET_API size_t ArenaPos(NonNullPtr arena); #if JULIET_DEBUG - struct ArenaDebugInfo; - JULIET_API String FormatDebugTagV(const char* formatStr, std::format_args args); +template #endif +[[nodiscard]] inline void* ArenaPushSize(NonNullPtr arena, size_t size, size_t align, + bool shouldBeZeroed JULIET_DEBUG_PARAM(FirstDebugArg&& firstDebugArg, + DebugArgs&&... debugArgs)) +{ + return ArenaPush(arena, size, align, + shouldBeZeroed JULIET_DEBUG_PARAM( + [&]() -> const char* + { + return Format(GetDebugInfoArena(), std::forward(firstDebugArg), + std::forward(debugArgs)...) + .Str; + }())); +} - struct Arena - { - Arena* Previous; - Arena* Current; - - uint64 BasePosition; - uint64 Position; - uint64 Alignment; - - uint64 CommitSize; - uint64 ReserveSize; - - uint64 Committed; - uint64 Reserved; - - Arena* FreeBlockLast; - - JULIET_DEBUG_ONLY(uint16 LostNodeCount;) - JULIET_DEBUG_ONLY(bool CanReserveMore : 1;) - - JULIET_DEBUG_ONLY(Arena* GlobalNext;) - JULIET_DEBUG_ONLY(Arena* GlobalPrev;) - JULIET_DEBUG_ONLY(ArenaDebugInfo* FirstDebugInfo;) - const char* Name; - }; - static_assert(sizeof(Arena) <= k_ArenaHeaderSize); - - struct TempArena - { - Arena* Arena; - index_t Position; - }; - - struct ArenaParams - { - uint64 ReserveSize = g_Arena_Default_Reserve_Size; - uint64 CommitSize = g_Arena_Default_Commit_Size; - - const char* Name; - - // When false, will assert if a new block is reserved. - JULIET_DEBUG_ONLY(bool CanReserveMore : 1 = true;) - }; - - [[nodiscard]] JULIET_API Arena* ArenaAllocate(const ArenaParams& params, - const std::source_location& loc = std::source_location::current()); - JULIET_API void ArenaRelease(NonNullPtr arena); - - // Raw Push, can be used but templated helpers exists below - [[nodiscard]] JULIET_API void* ArenaPush(NonNullPtr arena, size_t size, size_t align, - bool shouldBeZeroed JULIET_DEBUG_PARAM(const char* tag)); - JULIET_API void ArenaPopTo(NonNullPtr arena, size_t position); - JULIET_API void ArenaPop(NonNullPtr arena, size_t amount); - JULIET_API void ArenaClear(NonNullPtr arena); - [[nodiscard]] JULIET_API size_t ArenaPos(NonNullPtr arena); - -#if JULIET_DEBUG - template -#endif - [[nodiscard]] inline void* ArenaPushSize(NonNullPtr arena, size_t size, size_t align, - bool shouldBeZeroed JULIET_DEBUG_PARAM(FirstDebugArg&& firstDebugArg, - DebugArgs&&... debugArgs)) - { - return ArenaPush(arena, size, align, - shouldBeZeroed JULIET_DEBUG_PARAM( - [&]() -> const char* - { - return Format(GetDebugInfoArena(), std::forward(firstDebugArg), - std::forward(debugArgs)...) - .Str; - }())); - } - - template - [[nodiscard]] Type* ArenaPushStruct(NonNullPtr arena JULIET_DEBUG_PARAM(DebugArgs&&... debugArgs)) - { - return static_cast( - ArenaPush(arena, sizeof(Type) * 1, AlignOf(Type), - true JULIET_DEBUG_PARAM( - [&]() -> const char* +template +[[nodiscard]] Type* ArenaPushStruct(NonNullPtr arena JULIET_DEBUG_PARAM(DebugArgs&&... debugArgs)) +{ + return static_cast( + ArenaPush(arena, sizeof(Type) * 1, AlignOf(Type), + true JULIET_DEBUG_PARAM( + [&]() -> const char* + { + if constexpr (sizeof...(DebugArgs) > 0) { - if constexpr (sizeof...(DebugArgs) > 0) - { - return Format(GetDebugInfoArena(), std::forward(debugArgs)...).Str; - } - return GetTypeName(); - }()))); - } + return Format(GetDebugInfoArena(), std::forward(debugArgs)...).Str; + } + return GetTypeName(); + }()))); +} - template - [[nodiscard]] Type* ArenaPushArray(NonNullPtr arena, size_t count JULIET_DEBUG_PARAM(DebugArgs&&... debugArgs)) - { - return static_cast( - ArenaPush(arena, sizeof(Type) * count, Max(8ull, AlignOf(Type)), - shouldZero JULIET_DEBUG_PARAM( - [&]() -> const char* +template +[[nodiscard]] Type* ArenaPushArray(NonNullPtr arena, size_t count JULIET_DEBUG_PARAM(DebugArgs&&... debugArgs)) +{ + return static_cast( + ArenaPush(arena, sizeof(Type) * count, Max(8ull, AlignOf(Type)), + shouldZero JULIET_DEBUG_PARAM( + [&]() -> const char* + { + if constexpr (sizeof...(DebugArgs) > 0) { - if constexpr (sizeof...(DebugArgs) > 0) - { - return Format(GetDebugInfoArena(), std::forward(debugArgs)...).Str; - } - return GetTypeName(); - }()))); - } + return Format(GetDebugInfoArena(), std::forward(debugArgs)...).Str; + } + return GetTypeName(); + }()))); +} - TempArena ArenaTempBegin(NonNullPtr arena); - void ArenaTempEnd(TempArena temp); -} // namespace Juliet +TempArena ArenaTempBegin(NonNullPtr arena); +void ArenaTempEnd(TempArena temp); diff --git a/Juliet/include/Core/Memory/MemoryArenaDebug.h b/Juliet/include/Core/Memory/MemoryArenaDebug.h index 1fe8464..2793768 100644 --- a/Juliet/include/Core/Memory/MemoryArenaDebug.h +++ b/Juliet/include/Core/Memory/MemoryArenaDebug.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -7,46 +7,43 @@ #if JULIET_DEBUG -namespace Juliet +struct Arena; +struct MemoryBlock; + +// Arena (Struct) +struct ArenaDebugInfo { - struct Arena; - struct MemoryBlock; + const char* Tag; + size_t Offset; + size_t Size; + ArenaDebugInfo* Next; +}; - // Arena (Struct) - struct ArenaDebugInfo - { - const char* Tag; - size_t Offset; - size_t Size; - ArenaDebugInfo* Next; - }; +// MemoryArena (Pool-based) +struct ArenaAllocation +{ + size_t Offset; + size_t Size; + String Tag; + ArenaAllocation* Next; +}; - // MemoryArena (Pool-based) - struct ArenaAllocation - { - size_t Offset; - size_t Size; - String Tag; - ArenaAllocation* Next; - }; +// Arena (Struct) +void DebugRegisterArena(NonNullPtr arena); +void DebugUnregisterArena(NonNullPtr arena); +void DebugArenaSetDebugName(NonNullPtr arena, const char* name); +bool IsDebugInfoArena(const Arena* arena); // To prevent recursion +void DebugArenaFreeBlock(Arena* block); // To clear all debug infos in a block +void DebugArenaRemoveAllocation(Arena* block, size_t oldOffset); +void DebugArenaPopTo(Arena* block, size_t newPosition); +void DebugArenaAddDebugInfo(Arena* block, size_t size, size_t offset, const char* tag); - // Arena (Struct) - void DebugRegisterArena(NonNullPtr arena); - void DebugUnregisterArena(NonNullPtr arena); - void DebugArenaSetDebugName(NonNullPtr arena, const char* name); - bool IsDebugInfoArena(const Arena* arena); // To prevent recursion - void DebugArenaFreeBlock(Arena* block); // To clear all debug infos in a block - void DebugArenaRemoveAllocation(Arena* block, size_t oldOffset); - void DebugArenaPopTo(Arena* block, size_t newPosition); - void DebugArenaAddDebugInfo(Arena* block, size_t size, size_t offset, const char* tag); +// MemoryArena (Pool-based) +void DebugFreeArenaAllocations(MemoryBlock* blk); +void DebugArenaAddAllocation(MemoryBlock* blk, size_t size, size_t offset, String tag); +void DebugArenaRemoveLastAllocation(MemoryBlock* blk); - // MemoryArena (Pool-based) - void DebugFreeArenaAllocations(MemoryBlock* blk); - void DebugArenaAddAllocation(MemoryBlock* blk, size_t size, size_t offset, String tag); - void DebugArenaRemoveLastAllocation(MemoryBlock* blk); +JULIET_API Arena* GetDebugInfoArena(); - JULIET_API Arena* GetDebugInfoArena(); - -} // namespace Juliet #endif diff --git a/Juliet/include/Core/Memory/ScratchArena.h b/Juliet/include/Core/Memory/ScratchArena.h deleted file mode 100644 index e69de29..0000000 diff --git a/Juliet/include/Core/Memory/Utils.h b/Juliet/include/Core/Memory/Utils.h index 1711f24..f02697f 100644 --- a/Juliet/include/Core/Memory/Utils.h +++ b/Juliet/include/Core/Memory/Utils.h @@ -1,78 +1,75 @@ -#pragma once +#pragma once #include #define ArraySize(array) (sizeof(array) / sizeof(array[0])) -namespace Juliet +inline int32 MemCompare(const void* leftValue, const void* rightValue, size_t size) { - inline int32 MemCompare(const void* leftValue, const void* rightValue, size_t size) + auto left = static_cast(leftValue); + auto right = static_cast(rightValue); + while (size && *left == *right) { - auto left = static_cast(leftValue); - auto right = static_cast(rightValue); - while (size && *left == *right) - { - ++left; - ++right; - --size; - } - return size ? *left - *right : 0; + ++left; + ++right; + --size; + } + return size ? *left - *right : 0; +} + +// Single linked list +void SingleLinkedListPushNext(auto*& stackTop, auto* node) +{ + node->Next = stackTop; + stackTop = node; +} + +void SingleLinkedListPushPrevious(auto*& stackTop, auto* node) +{ + node->Previous = stackTop; + stackTop = node; +} + +void SingleLinkedListPopNext(auto*& stackTop) +{ + stackTop = stackTop->Next; +} + +// Double linked list +template +void Enqueue(QueueType& queue, QueueTypeNode* node) +{ + if (queue.First == nullptr) + { + queue.First = queue.Last = node; + node->Next = nullptr; + } + else + { + queue.Last->Next = node, queue.Last = node; + node->Next = nullptr; } - // Single linked list - void SingleLinkedListPushNext(auto*& stackTop, auto* node) - { - node->Next = stackTop; - stackTop = node; - } + queue.Nodecount += 1; +} - void SingleLinkedListPushPrevious(auto*& stackTop, auto* node) - { - node->Previous = stackTop; - stackTop = node; - } - - void SingleLinkedListPopNext(auto*& stackTop) - { - stackTop = stackTop->Next; - } - - // Double linked list - template - void Enqueue(QueueType& queue, QueueTypeNode* node) - { - if (queue.First == nullptr) - { - queue.First = queue.Last = node; - node->Next = nullptr; - } - else - { - queue.Last->Next = node, queue.Last = node; - node->Next = nullptr; - } - - queue.Nodecount += 1; - } - - template - struct QueueNode - { - QueueType* Next; - }; +template +struct QueueNode +{ + QueueType* Next; +}; #define DECLARE_QUEUE(type) \ - struct type##Queue \ - { \ - type* First; \ - type* Last; \ - size_t Nodecount; \ - size_t Size; \ - }; +struct type##Queue \ +{ \ + type* First; \ + type* Last; \ + size_t Nodecount; \ + size_t Size; \ +}; // TODO: homemade versions #define MemSet memset #define MemCopy memcpy #define MemoryZero(dst, size) MemSet(dst, 0, size) -} // namespace Juliet diff --git a/Juliet/include/Core/Networking/IPAddress.h b/Juliet/include/Core/Networking/IPAddress.h index 64b945e..441dbc4 100644 --- a/Juliet/include/Core/Networking/IPAddress.h +++ b/Juliet/include/Core/Networking/IPAddress.h @@ -1,11 +1,8 @@ -#pragma once +#pragma once #include -namespace Juliet -{ - // TODO : Do something better. - constexpr uint32 kLocalhost = (127 << 3) | (0 << 2) | (0 << 1) | 1; - constexpr uint32 kAnyIp = 0; - constexpr uint32 kBroadcastIp = (255 << 3) | (255 << 2) | (255 << 1) | 255; -} // namespace Juliet +// TODO : Do something better. +constexpr uint32 kLocalhost = (127 << 3) | (0 << 2) | (0 << 1) | 1; +constexpr uint32 kAnyIp = 0; +constexpr uint32 kBroadcastIp = (255 << 3) | (255 << 2) | (255 << 1) | 255; diff --git a/Juliet/include/Core/Networking/NetworkPacket.h b/Juliet/include/Core/Networking/NetworkPacket.h index 7709482..1d99295 100644 --- a/Juliet/include/Core/Networking/NetworkPacket.h +++ b/Juliet/include/Core/Networking/NetworkPacket.h @@ -1,36 +1,33 @@ -#pragma once +#pragma once #include #include -namespace Juliet +class NetworkPacket { - class NetworkPacket - { - public: - NetworkPacket(); - NetworkPacket(Arena& arena); - virtual ~NetworkPacket(); - NetworkPacket(NetworkPacket&); - NetworkPacket& operator=(const NetworkPacket&); - NetworkPacket(NetworkPacket&&) noexcept; - NetworkPacket& operator=(NetworkPacket&&) noexcept; + public: + NetworkPacket(); + NetworkPacket(Arena& arena); + virtual ~NetworkPacket(); + NetworkPacket(NetworkPacket&); + NetworkPacket& operator=(const NetworkPacket&); + NetworkPacket(NetworkPacket&&) noexcept; + NetworkPacket& operator=(NetworkPacket&&) noexcept; - void Create(Arena& arena); + void Create(Arena& arena); - [[nodiscard]] ByteBuffer GetRawData(); + [[nodiscard]] ByteBuffer GetRawData(); - // Pack - NetworkPacket& operator<<(uint32 value); - NetworkPacket& operator<<(char* data); + // Pack + NetworkPacket& operator<<(uint32 value); + NetworkPacket& operator<<(char* data); - protected: - void Append(ByteBuffer buffer); + protected: + void Append(ByteBuffer buffer); - friend class TcpSocket; + friend class TcpSocket; - private: - VectorArena Data; - size_t PartialSendIndex = 0; - }; -} // namespace Juliet + private: + VectorArena Data; + size_t PartialSendIndex = 0; +}; diff --git a/Juliet/include/Core/Networking/Socket.h b/Juliet/include/Core/Networking/Socket.h index d7a3f4d..92a67b7 100644 --- a/Juliet/include/Core/Networking/Socket.h +++ b/Juliet/include/Core/Networking/Socket.h @@ -1,56 +1,53 @@ -#pragma once +#pragma once #include -namespace Juliet +class Socket { - class Socket + public: + virtual ~Socket(); + + Socket(Socket&& other) noexcept; + Socket& operator=(Socket&& socket) noexcept; + + Socket(const Socket&) = delete; + Socket& operator=(const Socket&) = delete; + + bool IsValid() const; + + enum class Status : uint8 { - public: - virtual ~Socket(); - - Socket(Socket&& other) noexcept; - Socket& operator=(Socket&& socket) noexcept; - - Socket(const Socket&) = delete; - Socket& operator=(const Socket&) = delete; - - bool IsValid() const; - - enum class Status : uint8 - { - Done, - Partial, - Ready, - NotReady, - Disconnected, - Error - }; - - protected: - enum class Protocol : uint8 - { - TCP, - UDP - }; - - // To store the result of a send/receive on the socket - struct RequestStatus - { - Status Status = Status::Done; - size_t Length = 0; - }; - - explicit Socket(Protocol protocol); - - SocketHandle GetHandle() const { return Handle; } - - void Create(); - void CreateFromHandle(SocketHandle handle); - void Close(); - - private: - SocketHandle Handle; - Protocol ProtocolType; + Done, + Partial, + Ready, + NotReady, + Disconnected, + Error }; -} // namespace Juliet + + protected: + enum class Protocol : uint8 + { + TCP, + UDP + }; + + // To store the result of a send/receive on the socket + struct RequestStatus + { + Status Status = Status::Done; + size_t Length = 0; + }; + + explicit Socket(Protocol protocol); + + SocketHandle GetHandle() const { return Handle; } + + void Create(); + void CreateFromHandle(SocketHandle handle); + void Close(); + + private: + SocketHandle Handle; + Protocol ProtocolType; +}; diff --git a/Juliet/include/Core/Networking/SocketHandle.h b/Juliet/include/Core/Networking/SocketHandle.h index d8f6538..bc5ff98 100644 --- a/Juliet/include/Core/Networking/SocketHandle.h +++ b/Juliet/include/Core/Networking/SocketHandle.h @@ -1,14 +1,11 @@ -#pragma once +#pragma once #if JULIET_WIN32 #include #endif -namespace Juliet -{ #if JULIET_WIN32 - using SocketHandle = UINT_PTR; +using SocketHandle = UINT_PTR; #else - using SocketHandle = int; +using SocketHandle = int; #endif -} // namespace Juliet diff --git a/Juliet/include/Core/Networking/TcpListener.h b/Juliet/include/Core/Networking/TcpListener.h index 3f47300..ac5ce16 100644 --- a/Juliet/include/Core/Networking/TcpListener.h +++ b/Juliet/include/Core/Networking/TcpListener.h @@ -1,21 +1,18 @@ -#pragma once +#pragma once #include #include #include -namespace Juliet +class TcpListener : public Socket { - class TcpListener : public Socket - { - public: - TcpListener(); + public: + TcpListener(); - TcpListener(const TcpListener&) = delete; - TcpListener& operator=(const TcpListener&) = delete; + TcpListener(const TcpListener&) = delete; + TcpListener& operator=(const TcpListener&) = delete; - Status Listen(uint16 port, uint32 address = kAnyIp); - Status Accept(TcpSocket& socket); - void Close(); - }; -} // namespace Juliet + Status Listen(uint16 port, uint32 address = kAnyIp); + Status Accept(TcpSocket& socket); + void Close(); +}; diff --git a/Juliet/include/Core/Networking/TcpSocket.h b/Juliet/include/Core/Networking/TcpSocket.h index 8c93d61..8c4bf1e 100644 --- a/Juliet/include/Core/Networking/TcpSocket.h +++ b/Juliet/include/Core/Networking/TcpSocket.h @@ -1,24 +1,21 @@ -#pragma once +#pragma once #include -namespace Juliet +class NetworkPacket; + +class TcpSocket : public Socket { - class NetworkPacket; + public: + TcpSocket(); - class TcpSocket : public Socket - { - public: - TcpSocket(); + TcpSocket(const TcpSocket&) = delete; + TcpSocket& operator=(const TcpSocket&) = delete; - TcpSocket(const TcpSocket&) = delete; - TcpSocket& operator=(const TcpSocket&) = delete; + RequestStatus Send(NetworkPacket& packet); + RequestStatus Send(ByteBuffer buffer); + Status Receive(NetworkPacket& outPacket); - RequestStatus Send(NetworkPacket& packet); - RequestStatus Send(ByteBuffer buffer); - Status Receive(NetworkPacket& outPacket); - - private: - friend class TcpListener; - }; -} // namespace Juliet + private: + friend class TcpListener; +}; diff --git a/Juliet/include/Core/PCH.h b/Juliet/include/Core/PCH.h index 6ccdc20..7ac627b 100644 --- a/Juliet/include/Core/PCH.h +++ b/Juliet/include/Core/PCH.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include diff --git a/Juliet/include/Core/Thread/Mutex.h b/Juliet/include/Core/Thread/Mutex.h index 4b3e0ad..80a65c5 100644 --- a/Juliet/include/Core/Thread/Mutex.h +++ b/Juliet/include/Core/Thread/Mutex.h @@ -1,7 +1,4 @@ -#pragma once +#pragma once -namespace Juliet -{ - using Mutex = std::mutex; - using LockGuard = std::lock_guard; -} // namespace Juliet +using Mutex = std::mutex; +using LockGuard = std::lock_guard; diff --git a/Juliet/include/Core/Thread/Thread.h b/Juliet/include/Core/Thread/Thread.h index 6919e62..91be4bc 100644 --- a/Juliet/include/Core/Thread/Thread.h +++ b/Juliet/include/Core/Thread/Thread.h @@ -1,19 +1,16 @@ -#pragma once +#pragma once #include -namespace Juliet +uint32 thread_id(); + +void set_thread_name(String name); + +// TODO : Proper wait +inline void wait_ms(int milliseconds) { - uint32 thread_id(); - - void set_thread_name(String name); - - // TODO : Proper wait - inline void wait_ms(int milliseconds) + clock_t start_time = clock(); + while (clock() < start_time + milliseconds) { - clock_t start_time = clock(); - while (clock() < start_time + milliseconds) - { - } } -} // namespace Juliet +} diff --git a/Juliet/include/Core/Thread/ThreadContext.h b/Juliet/include/Core/Thread/ThreadContext.h index c35097a..8dfb953 100644 --- a/Juliet/include/Core/Thread/ThreadContext.h +++ b/Juliet/include/Core/Thread/ThreadContext.h @@ -1,24 +1,21 @@ -#pragma once +#pragma once #include #include -namespace Juliet +struct thread_context { - struct thread_context - { - Arena* ScratchArenas[2]; + Arena* ScratchArenas[2]; - char ThreadName[64]; - uint8 ThreadNameSize; - }; + char ThreadName[64]; + uint8 ThreadNameSize; +}; - thread_context* thread_context_alloc(); - void thread_context_release(NonNullPtr ctx); - void thread_context_select(NonNullPtr ctx); - thread_context* thread_context_current(); +thread_context* thread_context_alloc(); +void thread_context_release(NonNullPtr ctx); +void thread_context_select(NonNullPtr ctx); +thread_context* thread_context_current(); - Arena* thread_context_get_scratch(Arena** conflicts, size_t count); - TempArena scratch_begin(Arena** conflicts, size_t count); - void scratch_end(TempArena scratch); -} // namespace Juliet +Arena* thread_context_get_scratch(Arena** conflicts, size_t count); +TempArena scratch_begin(Arena** conflicts, size_t count); +void scratch_end(TempArena scratch); diff --git a/Juliet/include/Engine/Asset.h b/Juliet/include/Engine/Asset.h index 09950e6..903389e 100644 --- a/Juliet/include/Engine/Asset.h +++ b/Juliet/include/Engine/Asset.h @@ -1,9 +1,6 @@ -#pragma once +#pragma once #include #include -namespace Juliet -{ - JULIET_API extern MeshAssetID LoadMesh(String filename); -} +JULIET_API extern MeshAssetID LoadMesh(String filename); diff --git a/Juliet/include/Engine/Class.h b/Juliet/include/Engine/Class.h index 2b90b63..ec8b59b 100644 --- a/Juliet/include/Engine/Class.h +++ b/Juliet/include/Engine/Class.h @@ -1,33 +1,30 @@ -#pragma once +#pragma once #include #include -namespace Juliet +struct Class { - struct Class + uint32 CRC; +#if JULIET_DEBUG + // TODO: string struct may be + const char* Name; + size_t Name_Length; +#endif + + consteval Class(const char* className, size_t name_length) { - uint32 CRC; + CRC = crc32(className, name_length); #if JULIET_DEBUG // TODO: string struct may be - const char* Name; - size_t Name_Length; + Name = className; + Name_Length = name_length; #endif - - consteval Class(const char* className, size_t name_length) - { - CRC = crc32(className, name_length); -#if JULIET_DEBUG - // TODO: string struct may be - Name = className; - Name_Length = name_length; -#endif - } - }; - - template - bool IsA(Class& cls) - { - return cls.CRC == type::StaticClass->CRC; } -} // namespace Juliet +}; + +template +bool IsA(Class& cls) +{ + return cls.CRC == type::StaticClass->CRC; +} diff --git a/Juliet/include/Engine/Debug/MemoryDebugger.h b/Juliet/include/Engine/Debug/MemoryDebugger.h index b586d37..08285cf 100644 --- a/Juliet/include/Engine/Debug/MemoryDebugger.h +++ b/Juliet/include/Engine/Debug/MemoryDebugger.h @@ -1,12 +1,12 @@ -#pragma once +#pragma once #include #if JULIET_DEBUG -namespace Juliet::Debug +namespace Debug { JULIET_API void DebugDrawMemoryArena(); -} // namespace Juliet::Debug +} // namespace Debug #endif diff --git a/Juliet/include/Engine/Engine.h b/Juliet/include/Engine/Engine.h index 473c58c..e28d243 100644 --- a/Juliet/include/Engine/Engine.h +++ b/Juliet/include/Engine/Engine.h @@ -1,25 +1,22 @@ -#pragma once +#pragma once #include -namespace Juliet +enum class JulietInit_Flags : uint8; + +struct Engine { - enum class JulietInit_Flags : uint8; + IApplication* Application = nullptr; + Arena* PlatformArena = nullptr; + Arena* AssetArena = nullptr; +}; - struct Engine - { - IApplication* Application = nullptr; - Arena* PlatformArena = nullptr; - Arena* AssetArena = nullptr; - }; +void InitializeEngine(JulietInit_Flags flags); +void ShutdownEngine(); - void InitializeEngine(JulietInit_Flags flags); - void ShutdownEngine(); +void LoadApplication(IApplication& app); +void UnloadApplication(); - void LoadApplication(IApplication& app); - void UnloadApplication(); +void RunEngine(); - void RunEngine(); - - extern Arena* GetPlatformArena(); -} // namespace Juliet +extern Arena* GetPlatformArena(); diff --git a/Juliet/include/Graphics/Camera.h b/Juliet/include/Graphics/Camera.h index 0040636..a028a52 100644 --- a/Juliet/include/Graphics/Camera.h +++ b/Juliet/include/Graphics/Camera.h @@ -1,38 +1,35 @@ -#pragma once +#pragma once #include #include -namespace Juliet +struct Camera { - struct Camera - { - index_t Index; - Vector3 Position; - Vector3 Target; - Vector3 Up; - float FOV; // In radians - float AspectRatio; - float NearPlane; - float FarPlane; - }; + index_t Index; + Vector3 Position; + Vector3 Target; + Vector3 Up; + float FOV; // In radians + float AspectRatio; + float NearPlane; + float FarPlane; +}; - inline Matrix Camera_GetViewMatrix(const Camera& cam) - { - return LookAt(cam.Position, cam.Target, cam.Up); - } +inline Matrix Camera_GetViewMatrix(const Camera& cam) +{ + return LookAt(cam.Position, cam.Target, cam.Up); +} - inline Matrix Camera_GetProjectionMatrix(const Camera& cam) - { - return PerspectiveFov(cam.FOV, cam.AspectRatio, cam.NearPlane, cam.FarPlane); - } +inline Matrix Camera_GetProjectionMatrix(const Camera& cam) +{ + return PerspectiveFov(cam.FOV, cam.AspectRatio, cam.NearPlane, cam.FarPlane); +} - inline Matrix Camera_GetViewProjectionMatrix(const Camera& cam) - { - return Camera_GetProjectionMatrix(cam) * Camera_GetViewMatrix(cam); - } +inline Matrix Camera_GetViewProjectionMatrix(const Camera& cam) +{ + return Camera_GetProjectionMatrix(cam) * Camera_GetViewMatrix(cam); +} - JULIET_API extern void ReserveCamera(size_t amount); - JULIET_API extern Camera* GetCurrentCamera(); - JULIET_API extern void SetCurrentCamera(index_t index); -} // namespace Juliet +JULIET_API extern void ReserveCamera(size_t amount); +JULIET_API extern Camera* GetCurrentCamera(); +JULIET_API extern void SetCurrentCamera(index_t index); diff --git a/Juliet/include/Graphics/Colors.h b/Juliet/include/Graphics/Colors.h index eae255b..7f22a63 100644 --- a/Juliet/include/Graphics/Colors.h +++ b/Juliet/include/Graphics/Colors.h @@ -1,16 +1,13 @@ -#pragma once +#pragma once -namespace Juliet +template +struct ColorType { - template - struct ColorType - { - Type R; - Type G; - Type B; - Type A; - }; + Type R; + Type G; + Type B; + Type A; +}; - using FColor = ColorType; - using Color = ColorType; -} // namespace Juliet +using FColor = ColorType; +using Color = ColorType; diff --git a/Juliet/include/Graphics/DebugDisplay.h b/Juliet/include/Graphics/DebugDisplay.h index 951745b..98b0fa9 100644 --- a/Juliet/include/Graphics/DebugDisplay.h +++ b/Juliet/include/Graphics/DebugDisplay.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -6,12 +6,9 @@ #include #include -namespace Juliet -{ - extern JULIET_API void DebugDisplay_Initialize(NonNullPtr arena, GraphicsDevice* device); - extern JULIET_API void DebugDisplay_Shutdown(GraphicsDevice* device); - extern JULIET_API void DebugDisplay_DrawLine(const Vector3& start, const Vector3& end, const FColor& color, bool overlay); - extern JULIET_API void DebugDisplay_DrawSphere(const Vector3& center, float radius, const FColor& color, bool overlay); - extern JULIET_API void DebugDisplay_Prepare(CommandList* cmdList); - extern JULIET_API void DebugDisplay_Flush(CommandList* cmdList, RenderPass* renderPass, const Camera& camera); -} // namespace Juliet +extern JULIET_API void DebugDisplay_Initialize(NonNullPtr arena, GraphicsDevice* device); +extern JULIET_API void DebugDisplay_Shutdown(GraphicsDevice* device); +extern JULIET_API void DebugDisplay_DrawLine(const Vector3& start, const Vector3& end, const FColor& color, bool overlay); +extern JULIET_API void DebugDisplay_DrawSphere(const Vector3& center, float radius, const FColor& color, bool overlay); +extern JULIET_API void DebugDisplay_Prepare(CommandList* cmdList); +extern JULIET_API void DebugDisplay_Flush(CommandList* cmdList, RenderPass* renderPass, const Camera& camera); diff --git a/Juliet/include/Graphics/Graphics.h b/Juliet/include/Graphics/Graphics.h index c740736..76e9378 100644 --- a/Juliet/include/Graphics/Graphics.h +++ b/Juliet/include/Graphics/Graphics.h @@ -12,166 +12,163 @@ #include // Graphics Interface -namespace Juliet +// Opaque types +struct CommandList; +struct GraphicsDevice; +struct Fence; + +// Parameters of an indirect draw command +struct IndirectDrawCommand { - // Opaque types - struct CommandList; - struct GraphicsDevice; - struct Fence; + uint32 VertexCount; // Number of vertices to draw + uint32 InstanceCount; // Number of instanced to draw + uint32 FirstVertex; // Index of the first vertex to draw + uint32 FirstInstance; // ID of the first instance to draw +}; - // Parameters of an indirect draw command - struct IndirectDrawCommand - { - uint32 VertexCount; // Number of vertices to draw - uint32 InstanceCount; // Number of instanced to draw - uint32 FirstVertex; // Index of the first vertex to draw - uint32 FirstInstance; // ID of the first instance to draw - }; +// Parameters of an INDEXED indirect draw command +struct IndexedIndirectDrawCommand +{ + uint32 VertexCount; // Number of vertices to draw + uint32 InstanceCount; // Number of instanced to draw + uint32 FirstIndex; // Base Index within the index buffer + int32 VertexOffset; // Offset the vertex index into the buffer + uint32 FirstInstance; // ID of the first instance to draw +}; - // Parameters of an INDEXED indirect draw command - struct IndexedIndirectDrawCommand - { - uint32 VertexCount; // Number of vertices to draw - uint32 InstanceCount; // Number of instanced to draw - uint32 FirstIndex; // Base Index within the index buffer - int32 VertexOffset; // Offset the vertex index into the buffer - uint32 FirstInstance; // ID of the first instance to draw - }; +// Parameters of an INDEXED Indirect Dispatch Command +struct IndirectDispatchCommand +{ + uint32 X_WorkGroupCount; // Number of Workgroup to dispatch on dimension X + uint32 Y_WorkGroupCount; // Number of Workgroup to dispatch on dimension Y + uint32 Z_WorkGroupCount; // Number of Workgroup to dispatch on dimension Z +}; - // Parameters of an INDEXED Indirect Dispatch Command - struct IndirectDispatchCommand - { - uint32 X_WorkGroupCount; // Number of Workgroup to dispatch on dimension X - uint32 Y_WorkGroupCount; // Number of Workgroup to dispatch on dimension Y - uint32 Z_WorkGroupCount; // Number of Workgroup to dispatch on dimension Z - }; +enum class QueueType : uint8 +{ + Graphics = 0, + Compute, + Copy, + Count +}; - enum class QueueType : uint8 - { - Graphics = 0, - Compute, - Copy, - Count - }; +enum class IndexFormat : uint8 +{ + UInt16, + UInt32 +}; - enum class IndexFormat : uint8 - { - UInt16, - UInt32 - }; +enum struct SwapChainComposition : uint8 +{ + SDR, + SDR_LINEAR, + HDR_EXTENDED_LINEAR, + HDR10_ST2084 +}; - enum struct SwapChainComposition : uint8 - { - SDR, - SDR_LINEAR, - HDR_EXTENDED_LINEAR, - HDR10_ST2084 - }; +// PresentMode from highest to lowest latency +// Vsync prevents tearing. Enqueue ready images. +// Mailbox prevents tearing. When image is ready, replace any pending image +// Immediate replace current image as soon as possible. Can cause tearing +enum struct PresentMode : uint8 +{ + VSync, + Mailbox, + Immediate +}; - // PresentMode from highest to lowest latency - // Vsync prevents tearing. Enqueue ready images. - // Mailbox prevents tearing. When image is ready, replace any pending image - // Immediate replace current image as soon as possible. Can cause tearing - enum struct PresentMode : uint8 - { - VSync, - Mailbox, - Immediate - }; +struct GraphicsViewPort +{ + float X; + float Y; + float Width; + float Height; + float MinDepth; + float MaxDepth; +}; - struct GraphicsViewPort - { - float X; - float Y; - float Width; - float Height; - float MinDepth; - float MaxDepth; - }; +extern JULIET_API GraphicsDevice* CreateGraphicsDevice(GraphicsConfig config); +extern JULIET_API void DestroyGraphicsDevice(NonNullPtr device); - extern JULIET_API GraphicsDevice* CreateGraphicsDevice(GraphicsConfig config); - extern JULIET_API void DestroyGraphicsDevice(NonNullPtr device); +// Attach To Window +extern JULIET_API bool AttachToWindow(NonNullPtr device, NonNullPtr window); +extern JULIET_API void DetachFromWindow(NonNullPtr device, NonNullPtr window); - // Attach To Window - extern JULIET_API bool AttachToWindow(NonNullPtr device, NonNullPtr window); - extern JULIET_API void DetachFromWindow(NonNullPtr device, NonNullPtr window); +// SwapChain +extern JULIET_API bool AcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, + Texture** swapChainTexture); +extern JULIET_API bool WaitAndAcquireSwapChainTexture(NonNullPtr commandList, + NonNullPtr window, Texture** swapChainTexture); +extern JULIET_API bool WaitForSwapchain(NonNullPtr device, NonNullPtr window); +extern JULIET_API TextureFormat GetSwapChainTextureFormat(NonNullPtr device, NonNullPtr window); - // SwapChain - extern JULIET_API bool AcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, - Texture** swapChainTexture); - extern JULIET_API bool WaitAndAcquireSwapChainTexture(NonNullPtr commandList, - NonNullPtr window, Texture** swapChainTexture); - extern JULIET_API bool WaitForSwapchain(NonNullPtr device, NonNullPtr window); - extern JULIET_API TextureFormat GetSwapChainTextureFormat(NonNullPtr device, NonNullPtr window); +// Textures +extern JULIET_API Texture* CreateTexture(NonNullPtr device, const TextureCreateInfo& createInfo); +extern JULIET_API void DestroyTexture(NonNullPtr device, NonNullPtr texture); - // Textures - extern JULIET_API Texture* CreateTexture(NonNullPtr device, const TextureCreateInfo& createInfo); - extern JULIET_API void DestroyTexture(NonNullPtr device, NonNullPtr texture); +// Command List +extern JULIET_API CommandList* AcquireCommandList(NonNullPtr device, QueueType queueType = QueueType::Graphics); +extern JULIET_API void SubmitCommandLists(NonNullPtr commandList); - // Command List - extern JULIET_API CommandList* AcquireCommandList(NonNullPtr device, QueueType queueType = QueueType::Graphics); - extern JULIET_API void SubmitCommandLists(NonNullPtr commandList); +// RenderPass +extern JULIET_API RenderPass* BeginRenderPass(NonNullPtr commandList, ColorTargetInfo& colorTargetInfo, + DepthStencilTargetInfo* depthStencilTargetInfo = nullptr); +extern JULIET_API RenderPass* BeginRenderPass(NonNullPtr commandList, + NonNullPtr colorTargetInfos, uint32 colorTargetInfoCount, + DepthStencilTargetInfo* depthStencilTargetInfo = nullptr); +extern JULIET_API void EndRenderPass(NonNullPtr renderPass); - // RenderPass - extern JULIET_API RenderPass* BeginRenderPass(NonNullPtr commandList, ColorTargetInfo& colorTargetInfo, - DepthStencilTargetInfo* depthStencilTargetInfo = nullptr); - extern JULIET_API RenderPass* BeginRenderPass(NonNullPtr commandList, - NonNullPtr colorTargetInfos, uint32 colorTargetInfoCount, - DepthStencilTargetInfo* depthStencilTargetInfo = nullptr); - extern JULIET_API void EndRenderPass(NonNullPtr renderPass); +extern JULIET_API void SetGraphicsViewPort(NonNullPtr renderPass, const GraphicsViewPort& viewPort); +extern JULIET_API void SetScissorRect(NonNullPtr renderPass, const struct Rectangle& rectangle); +extern JULIET_API void SetBlendConstants(NonNullPtr renderPass, FColor blendConstants); +extern JULIET_API void SetStencilReference(NonNullPtr renderPass, uint8 reference); - extern JULIET_API void SetGraphicsViewPort(NonNullPtr renderPass, const GraphicsViewPort& viewPort); - extern JULIET_API void SetScissorRect(NonNullPtr renderPass, const Rectangle& rectangle); - extern JULIET_API void SetBlendConstants(NonNullPtr renderPass, FColor blendConstants); - extern JULIET_API void SetStencilReference(NonNullPtr renderPass, uint8 reference); +extern JULIET_API void BindGraphicsPipeline(NonNullPtr renderPass, NonNullPtr graphicsPipeline); +extern JULIET_API void DrawPrimitives(NonNullPtr renderPass, uint32 numVertices, uint32 numInstances, + uint32 firstVertex, uint32 firstInstance); +extern JULIET_API void DrawIndexedPrimitives(NonNullPtr renderPass, uint32 numIndices, uint32 numInstances, + uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance); - extern JULIET_API void BindGraphicsPipeline(NonNullPtr renderPass, NonNullPtr graphicsPipeline); - extern JULIET_API void DrawPrimitives(NonNullPtr renderPass, uint32 numVertices, uint32 numInstances, - uint32 firstVertex, uint32 firstInstance); - extern JULIET_API void DrawIndexedPrimitives(NonNullPtr renderPass, uint32 numIndices, uint32 numInstances, - uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance); +extern JULIET_API void SetIndexBuffer(NonNullPtr commandList, NonNullPtr buffer, + IndexFormat format, size_t indexCount, index_t offset); - extern JULIET_API void SetIndexBuffer(NonNullPtr commandList, NonNullPtr buffer, - IndexFormat format, size_t indexCount, index_t offset); +extern JULIET_API void SetPushConstants(NonNullPtr commandList, ShaderStage stage, + uint32 rootParameterIndex, uint32 numConstants, const void* constants); - extern JULIET_API void SetPushConstants(NonNullPtr commandList, ShaderStage stage, - uint32 rootParameterIndex, uint32 numConstants, const void* constants); +// Fences +extern JULIET_API bool WaitUntilGPUIsIdle(NonNullPtr device); - // Fences - extern JULIET_API bool WaitUntilGPUIsIdle(NonNullPtr device); +// Shaders +extern JULIET_API Shader* CreateShader(NonNullPtr device, String filename, ShaderCreateInfo& shaderCreateInfo); +extern JULIET_API void DestroyShader(NonNullPtr device, NonNullPtr shader); - // Shaders - extern JULIET_API Shader* CreateShader(NonNullPtr device, String filename, ShaderCreateInfo& shaderCreateInfo); - extern JULIET_API void DestroyShader(NonNullPtr device, NonNullPtr shader); - - // Pipelines - extern JULIET_API GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr device, - const GraphicsPipelineCreateInfo& createInfo); - extern JULIET_API void DestroyGraphicsPipeline(NonNullPtr device, NonNullPtr graphicsPipeline); +// Pipelines +extern JULIET_API GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr device, + const GraphicsPipelineCreateInfo& createInfo); +extern JULIET_API void DestroyGraphicsPipeline(NonNullPtr device, NonNullPtr graphicsPipeline); #if ALLOW_SHADER_HOT_RELOAD - // Allows updating the graphics pipeline shaders. Can update either one or both shaders. - extern JULIET_API bool UpdateGraphicsPipelineShaders(NonNullPtr device, NonNullPtr graphicsPipeline, - Shader* optional_vertexShader, Shader* optional_fragmentShader); +// Allows updating the graphics pipeline shaders. Can update either one or both shaders. +extern JULIET_API bool UpdateGraphicsPipelineShaders(NonNullPtr device, NonNullPtr graphicsPipeline, + Shader* optional_vertexShader, Shader* optional_fragmentShader); #endif - // Buffers - extern JULIET_API GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr device, const BufferCreateInfo& createInfo); - extern JULIET_API GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr device, - const TransferBufferCreateInfo& createInfo); - extern JULIET_API void* MapGraphicsBuffer(NonNullPtr device, NonNullPtr buffer); - extern JULIET_API void UnmapGraphicsBuffer(NonNullPtr device, NonNullPtr buffer); - extern JULIET_API void* MapGraphicsTransferBuffer(NonNullPtr device, NonNullPtr buffer); - extern JULIET_API void UnmapGraphicsTransferBuffer(NonNullPtr device, NonNullPtr buffer); - extern JULIET_API void CopyBuffer(NonNullPtr commandList, NonNullPtr dst, - NonNullPtr src, size_t size, size_t dstOffset = 0, - size_t srcOffset = 0); - extern JULIET_API void CopyBufferToTexture(NonNullPtr commandList, NonNullPtr dst, - NonNullPtr src); +// Buffers +extern JULIET_API GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr device, const BufferCreateInfo& createInfo); +extern JULIET_API GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr device, + const TransferBufferCreateInfo& createInfo); +extern JULIET_API void* MapGraphicsBuffer(NonNullPtr device, NonNullPtr buffer); +extern JULIET_API void UnmapGraphicsBuffer(NonNullPtr device, NonNullPtr buffer); +extern JULIET_API void* MapGraphicsTransferBuffer(NonNullPtr device, NonNullPtr buffer); +extern JULIET_API void UnmapGraphicsTransferBuffer(NonNullPtr device, NonNullPtr buffer); +extern JULIET_API void CopyBuffer(NonNullPtr commandList, NonNullPtr dst, + NonNullPtr src, size_t size, size_t dstOffset = 0, + size_t srcOffset = 0); +extern JULIET_API void CopyBufferToTexture(NonNullPtr commandList, NonNullPtr dst, + NonNullPtr src); - extern JULIET_API void TransitionBufferToReadable(NonNullPtr commandList, NonNullPtr buffer); - extern JULIET_API uint32 GetDescriptorIndex(NonNullPtr device, NonNullPtr buffer); - extern JULIET_API uint32 GetDescriptorIndex(NonNullPtr device, NonNullPtr texture); +extern JULIET_API void TransitionBufferToReadable(NonNullPtr commandList, NonNullPtr buffer); +extern JULIET_API uint32 GetDescriptorIndex(NonNullPtr device, NonNullPtr buffer); +extern JULIET_API uint32 GetDescriptorIndex(NonNullPtr device, NonNullPtr texture); - extern JULIET_API void DestroyGraphicsBuffer(NonNullPtr device, NonNullPtr buffer); - extern JULIET_API void DestroyGraphicsTransferBuffer(NonNullPtr device, NonNullPtr buffer); -} // namespace Juliet +extern JULIET_API void DestroyGraphicsBuffer(NonNullPtr device, NonNullPtr buffer); +extern JULIET_API void DestroyGraphicsTransferBuffer(NonNullPtr device, NonNullPtr buffer); diff --git a/Juliet/include/Graphics/GraphicsBuffer.h b/Juliet/include/Graphics/GraphicsBuffer.h index 2c719b1..e377c52 100644 --- a/Juliet/include/Graphics/GraphicsBuffer.h +++ b/Juliet/include/Graphics/GraphicsBuffer.h @@ -1,36 +1,33 @@ -#pragma once +#pragma once -namespace Juliet +enum class BufferUsage : uint8 { - enum class BufferUsage : uint8 - { - None = 0, - IndexBuffer = 1 << 0, - ConstantBuffer = 1 << 1, - StructuredBuffer = 1 << 2, - }; + None = 0, + IndexBuffer = 1 << 0, + ConstantBuffer = 1 << 1, + StructuredBuffer = 1 << 2, +}; - enum class TransferBufferUsage : uint8 - { - Download, - Upload - }; +enum class TransferBufferUsage : uint8 +{ + Download, + Upload +}; - struct BufferCreateInfo - { - size_t Size; - size_t Stride; - BufferUsage Usage; - bool IsDynamic; - }; +struct BufferCreateInfo +{ + size_t Size; + size_t Stride; + BufferUsage Usage; + bool IsDynamic; +}; - struct TransferBufferCreateInfo - { - size_t Size; - TransferBufferUsage Usage; - }; +struct TransferBufferCreateInfo +{ + size_t Size; + TransferBufferUsage Usage; +}; - // Opaque - struct GraphicsBuffer; - struct GraphicsTransferBuffer; -} // namespace Juliet +// Opaque +struct GraphicsBuffer; +struct GraphicsTransferBuffer; diff --git a/Juliet/include/Graphics/GraphicsConfig.h b/Juliet/include/Graphics/GraphicsConfig.h index 3ef8691..3364491 100644 --- a/Juliet/include/Graphics/GraphicsConfig.h +++ b/Juliet/include/Graphics/GraphicsConfig.h @@ -10,17 +10,14 @@ #define ALLOW_SHADER_HOT_RELOAD 0 #endif -namespace Juliet +enum class GraphicsDriverType : uint8 { - enum class DriverType : uint8 - { - Any = 0, - DX12 = 1, - }; + Any = 0, + DX12 = 1, +}; - struct GraphicsConfig - { - DriverType PreferredDriver = DriverType::DX12; - bool EnableDebug; - }; -} // namespace Juliet +struct GraphicsConfig +{ + GraphicsDriverType PreferredDriver = GraphicsDriverType::DX12; + bool EnableDebug; +}; diff --git a/Juliet/include/Graphics/GraphicsPipeline.h b/Juliet/include/Graphics/GraphicsPipeline.h index 492a000..f2410dc 100644 --- a/Juliet/include/Graphics/GraphicsPipeline.h +++ b/Juliet/include/Graphics/GraphicsPipeline.h @@ -1,225 +1,222 @@ -#pragma once +#pragma once #include #include -namespace Juliet +// Forward Declare +struct ColorTargetDescription; + +enum class FillMode : uint8 { - // Forward Declare - struct ColorTargetDescription; + Solid, + Wireframe, + Count +}; - enum class FillMode : uint8 - { - Solid, - Wireframe, - Count - }; +enum class CullMode : uint8 +{ + None, + Front, + Back, + Count +}; - enum class CullMode : uint8 - { - None, - Front, - Back, - Count - }; +enum class FrontFace : uint8 +{ + CounterClockwise, + Clockwise, + Count +}; - enum class FrontFace : uint8 - { - CounterClockwise, - Clockwise, - Count - }; +enum class PrimitiveType : uint8 +{ + TriangleList, + TriangleStrip, + LineList, + LineStrip, + PointList, + Count +}; - enum class PrimitiveType : uint8 - { - TriangleList, - TriangleStrip, - LineList, - LineStrip, - PointList, - Count - }; +struct RasterizerState +{ + FillMode FillMode; + CullMode CullMode; + FrontFace FrontFace; - struct RasterizerState - { - FillMode FillMode; - CullMode CullMode; - FrontFace FrontFace; + float DepthBiasConstantFactor; // How much depth value is added to each fragment + float DepthBiasClamp; // Maximum depth bias + float DepthBiasSlopeFactor; // Scalar applied to Fragment's slope + bool EnableDepthBias; // Bias fragment depth values + bool EnableDepthClip; // True to clip, false to clamp +}; - float DepthBiasConstantFactor; // How much depth value is added to each fragment - float DepthBiasClamp; // Maximum depth bias - float DepthBiasSlopeFactor; // Scalar applied to Fragment's slope - bool EnableDepthBias; // Bias fragment depth values - bool EnableDepthClip; // True to clip, false to clamp - }; +enum class VertexInputRate : uint8 +{ + Vertex, // Use vertex index + Instance, // Use instance index + Count +}; - enum class VertexInputRate : uint8 - { - Vertex, // Use vertex index - Instance, // Use instance index - Count - }; +struct VertexBufferDescription +{ + uint32 Slot; // Binding Slot + uint32 PitchInBytes; // Pitch between two elements + VertexInputRate InputRate; + uint32 InstanceStepRate; // Only used when input rate == Instance. Number of instances to draw before advancing in the instance buffer by 1 +}; - struct VertexBufferDescription - { - uint32 Slot; // Binding Slot - uint32 PitchInBytes; // Pitch between two elements - VertexInputRate InputRate; - uint32 InstanceStepRate; // Only used when input rate == Instance. Number of instances to draw before advancing in the instance buffer by 1 - }; +enum class VertexElementFormat : uint8 +{ + Invalid, - enum class VertexElementFormat : uint8 - { - Invalid, + /* 32-bit Signed Integers */ + Int, + Int2, + Int3, + Int4, - /* 32-bit Signed Integers */ - Int, - Int2, - Int3, - Int4, + /* 32-bit Unsigned Integers */ + UInt, + UInt2, + UInt3, + UInt4, - /* 32-bit Unsigned Integers */ - UInt, - UInt2, - UInt3, - UInt4, + /* 32-bit Floats */ + Float, + Float2, + Float3, + Float4, - /* 32-bit Floats */ - Float, - Float2, - Float3, - Float4, + /* 8-bit Signed Integers */ + Byte2, + Byte4, - /* 8-bit Signed Integers */ - Byte2, - Byte4, + /* 8-bit Unsigned Integers */ + UByte2, + UByte4, - /* 8-bit Unsigned Integers */ - UByte2, - UByte4, + /* 8-bit Signed Normalized */ + Byte2_Norm, + Byte4_Norm, - /* 8-bit Signed Normalized */ - Byte2_Norm, - Byte4_Norm, + /* 8-bit Unsigned Normalized */ + UByte2_Norm, + UByte4_Norm, - /* 8-bit Unsigned Normalized */ - UByte2_Norm, - UByte4_Norm, + /* 16-bit Signed Integers */ + Short2, + Short4, - /* 16-bit Signed Integers */ - Short2, - Short4, + /* 16-bit Unsigned Integers */ + UShort2, + UShort4, - /* 16-bit Unsigned Integers */ - UShort2, - UShort4, + /* 16-bit Signed Normalized */ + Short2_Norm, + Short4_Norm, - /* 16-bit Signed Normalized */ - Short2_Norm, - Short4_Norm, + /* 16-bit Unsigned Normalized */ + UShort2_Norm, + UShort4_Norm, - /* 16-bit Unsigned Normalized */ - UShort2_Norm, - UShort4_Norm, + /* 16-bit Floats */ + Half2, + Half4, - /* 16-bit Floats */ - Half2, - Half4, + // + Count +}; - // - Count - }; +struct VertexAttribute +{ + uint32 Location; // Shader input location index + uint32 BufferSlot; // Binding slot of associated vertex buffer + VertexElementFormat Format; // Size and type of attribute + uint32 Offset; // Offset of this attribute relative to the start of the vertex element +}; - struct VertexAttribute - { - uint32 Location; // Shader input location index - uint32 BufferSlot; // Binding slot of associated vertex buffer - VertexElementFormat Format; // Size and type of attribute - uint32 Offset; // Offset of this attribute relative to the start of the vertex element - }; +struct VertexInputState +{ + const VertexBufferDescription* VertexBufferDescriptions; + uint32 NumVertexBufferDescriptions; + const VertexAttribute* VertexAttributes; + uint32 NumVertexAttributes; +}; - struct VertexInputState - { - const VertexBufferDescription* VertexBufferDescriptions; - uint32 NumVertexBufferDescriptions; - const VertexAttribute* VertexAttributes; - uint32 NumVertexAttributes; - }; +struct GraphicsPipelineTargetInfo +{ + const ColorTargetDescription* ColorTargetDescriptions; + size_t NumColorTargets; + TextureFormat DepthStencilFormat; + bool HasDepthStencilTarget; +}; - struct GraphicsPipelineTargetInfo - { - const ColorTargetDescription* ColorTargetDescriptions; - size_t NumColorTargets; - TextureFormat DepthStencilFormat; - bool HasDepthStencilTarget; - }; +enum class CompareOperation : uint8 +{ + Invalid, + Never, // The comparison always evaluates false. + Less, // The comparison evaluates reference < test. + Equal, // The comparison evaluates reference == test. + LessOrEqual, // The comparison evaluates reference <= test. + Greater, // The comparison evaluates reference > test. + NotEqual, // The comparison evaluates reference != test. + GreaterOrEqual, // The comparison evalutes reference >= test. + Always, // The comparison always evaluates true. + Count +}; - enum class CompareOperation : uint8 - { - Invalid, - Never, // The comparison always evaluates false. - Less, // The comparison evaluates reference < test. - Equal, // The comparison evaluates reference == test. - LessOrEqual, // The comparison evaluates reference <= test. - Greater, // The comparison evaluates reference > test. - NotEqual, // The comparison evaluates reference != test. - GreaterOrEqual, // The comparison evalutes reference >= test. - Always, // The comparison always evaluates true. - Count - }; +enum class StencilOperation : uint8 +{ + Invalid, + Keep, // Keeps the current value. + Zero, // Sets the value to 0. + Replace, // Sets the value to reference. + IncrementAndClamp, // Increments the current value and clamps to the maximum value. + DecrementAndClamp, // Decrements the current value and clamps to 0. + Invert, // Bitwise-inverts the current value. + IncrementAndWrap, // Increments the current value and wraps back to 0. + DecrementAndWrap, // Decrements the current value and wraps to the maximum value. + Count +}; - enum class StencilOperation : uint8 - { - Invalid, - Keep, // Keeps the current value. - Zero, // Sets the value to 0. - Replace, // Sets the value to reference. - IncrementAndClamp, // Increments the current value and clamps to the maximum value. - DecrementAndClamp, // Decrements the current value and clamps to 0. - Invert, // Bitwise-inverts the current value. - IncrementAndWrap, // Increments the current value and wraps back to 0. - DecrementAndWrap, // Decrements the current value and wraps to the maximum value. - Count - }; +struct StencilOperationState +{ + StencilOperation FailOperation; // The action performed on samples that fail the stencil test. + StencilOperation PassOperation; // The action performed on samples that pass the depth and stencil tests. + StencilOperation DepthFailOperation; // The action performed on samples that pass the stencil test and fail the depth test. + StencilOperation CompareOperation; // The comparison operator used in the stencil test. +}; - struct StencilOperationState - { - StencilOperation FailOperation; // The action performed on samples that fail the stencil test. - StencilOperation PassOperation; // The action performed on samples that pass the depth and stencil tests. - StencilOperation DepthFailOperation; // The action performed on samples that pass the stencil test and fail the depth test. - StencilOperation CompareOperation; // The comparison operator used in the stencil test. - }; +struct DepthStencilState +{ + CompareOperation CompareOperation; // The comparison operator used for depth testing. + StencilOperationState BackStencilState; // The stencil op state for back-facing triangles. + StencilOperationState FrontStencilState; // The stencil op state for front-facing triangles. + uint8 CompareMask; // Selects the bits of the stencil values participating in the stencil test. + uint8 WriteMask; // Selects the bits of the stencil values updated by the stencil test. + bool EnableDepthTest : 1; // true enables the depth test. + bool EnableDepthWrite : 1; // true enables depth writes. Depth writes are always disabled when enable_depth_test is false. + bool EnableStencilTest : 1; // true enables the stencil test. +}; - struct DepthStencilState - { - CompareOperation CompareOperation; // The comparison operator used for depth testing. - StencilOperationState BackStencilState; // The stencil op state for back-facing triangles. - StencilOperationState FrontStencilState; // The stencil op state for front-facing triangles. - uint8 CompareMask; // Selects the bits of the stencil values participating in the stencil test. - uint8 WriteMask; // Selects the bits of the stencil values updated by the stencil test. - bool EnableDepthTest : 1; // true enables the depth test. - bool EnableDepthWrite : 1; // true enables depth writes. Depth writes are always disabled when enable_depth_test is false. - bool EnableStencilTest : 1; // true enables the stencil test. - }; +struct MultisampleState +{ + TextureSampleCount SampleCount; + uint32 SampleMask; // Which sample should be updated. If Enabled mask == false -> 0xFFFFFFFF + bool EnableMask; +}; - struct MultisampleState - { - TextureSampleCount SampleCount; - uint32 SampleMask; // Which sample should be updated. If Enabled mask == false -> 0xFFFFFFFF - bool EnableMask; - }; +struct GraphicsPipelineCreateInfo +{ + Shader* VertexShader; + Shader* FragmentShader; + PrimitiveType PrimitiveType; + GraphicsPipelineTargetInfo TargetInfo; + RasterizerState RasterizerState; + MultisampleState MultisampleState; + VertexInputState VertexInputState; + DepthStencilState DepthStencilState; +}; - struct GraphicsPipelineCreateInfo - { - Shader* VertexShader; - Shader* FragmentShader; - PrimitiveType PrimitiveType; - GraphicsPipelineTargetInfo TargetInfo; - RasterizerState RasterizerState; - MultisampleState MultisampleState; - VertexInputState VertexInputState; - DepthStencilState DepthStencilState; - }; - - // Opaque type - struct GraphicsPipeline; -} // namespace Juliet +// Opaque type +struct GraphicsPipeline; diff --git a/Juliet/include/Graphics/ImGuiRenderer.h b/Juliet/include/Graphics/ImGuiRenderer.h index f42fc6a..6298a5e 100644 --- a/Juliet/include/Graphics/ImGuiRenderer.h +++ b/Juliet/include/Graphics/ImGuiRenderer.h @@ -1,12 +1,9 @@ -#pragma once +#pragma once #include #include -namespace Juliet -{ - extern bool ImGuiRenderer_Initialize(GraphicsDevice* device); - extern void ImGuiRenderer_Shutdown(GraphicsDevice* device); - extern void ImGuiRenderer_NewFrame(); - extern JULIET_API void ImGuiRenderer_Render(CommandList* cmdList, RenderPass* renderPass); -} // namespace Juliet +extern bool ImGuiRenderer_Initialize(GraphicsDevice* device); +extern void ImGuiRenderer_Shutdown(GraphicsDevice* device); +extern void ImGuiRenderer_NewFrame(); +extern JULIET_API void ImGuiRenderer_Render(CommandList* cmdList, RenderPass* renderPass); diff --git a/Juliet/include/Graphics/Lighting.h b/Juliet/include/Graphics/Lighting.h index ef44c9e..cfd838b 100644 --- a/Juliet/include/Graphics/Lighting.h +++ b/Juliet/include/Graphics/Lighting.h @@ -1,15 +1,12 @@ -#pragma once +#pragma once #include #include -namespace Juliet +struct PointLight { - struct PointLight - { - Vector3 Position; - float Radius; - Vector3 Color; - float Intensity; - }; -} // namespace Juliet + Vector3 Position; + float Radius; + Vector3 Color; + float Intensity; +}; diff --git a/Juliet/include/Graphics/Mesh.h b/Juliet/include/Graphics/Mesh.h index 0f35410..267ea2b 100644 --- a/Juliet/include/Graphics/Mesh.h +++ b/Juliet/include/Graphics/Mesh.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -7,34 +7,31 @@ #include #include -namespace Juliet +struct Arena; +struct Vertex; + +using MeshAssetID = index_t; +using MaterialAssetID = index_t; +using MeshInstanceID = index_t; + +struct MeshAsset { - struct Arena; - struct Vertex; + String Name; + size_t VertexCount; + size_t IndexCount; - using MeshAssetID = index_t; - using MaterialAssetID = index_t; - using MeshInstanceID = index_t; + index_t VertexOffset; + index_t IndexOffset; +}; - struct MeshAsset - { - String Name; - size_t VertexCount; - size_t IndexCount; +struct MaterialAsset +{ + Vector4 AlbedoColor = {1.0f, 1.0f, 1.0f, 1.0f}; +}; - index_t VertexOffset; - index_t IndexOffset; - }; - - struct MaterialAsset - { - Vector4 AlbedoColor = {1.0f, 1.0f, 1.0f, 1.0f}; - }; - - struct MeshInstance - { - MeshAssetID MeshAsset; - MaterialAssetID MaterialAsset; - Matrix Transform = MatrixIdentity(); - }; -} // namespace Juliet +struct MeshInstance +{ + MeshAssetID MeshAsset; + MaterialAssetID MaterialAsset; + Matrix Transform = MatrixIdentity(); +}; diff --git a/Juliet/include/Graphics/MeshRenderer.h b/Juliet/include/Graphics/MeshRenderer.h index d949182..ddf8292 100644 --- a/Juliet/include/Graphics/MeshRenderer.h +++ b/Juliet/include/Graphics/MeshRenderer.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -9,52 +9,49 @@ #include #include -namespace Juliet -{ - struct GraphicsTransferBuffer; - struct RenderPass; - struct CommandList; - struct GraphicsBuffer; - struct Window; - struct GraphicsPipeline; - struct GraphicsDevice; - using LightID = index_t; +struct GraphicsTransferBuffer; +struct RenderPass; +struct CommandList; +struct GraphicsBuffer; +struct Window; +struct GraphicsPipeline; +struct GraphicsDevice; +using LightID = index_t; - constexpr size_t kGeometryPage = Megabytes(64); - constexpr size_t kIndexPage = Megabytes(32); - constexpr size_t kDefaultMeshNumber = 500; - constexpr size_t kDefaultVertexCount = 2'000'000; // Fit less than one geometry page - constexpr size_t kDefaultIndexCount = 16'000'000; // Fit less than one index page - constexpr size_t kDefaultLightCount = 1024; +constexpr size_t kGeometryPage = Megabytes(64); +constexpr size_t kIndexPage = Megabytes(32); +constexpr size_t kDefaultMeshNumber = 500; +constexpr size_t kDefaultVertexCount = 2'000'000; // Fit less than one geometry page +constexpr size_t kDefaultIndexCount = 16'000'000; // Fit less than one index page +constexpr size_t kDefaultLightCount = 1024; - JULIET_API void InitializeMeshRenderer(NonNullPtr assetArena, NonNullPtr instanceArena); - [[nodiscard]] JULIET_API bool InitializeMeshRendererGraphics(NonNullPtr device, NonNullPtr window); - JULIET_API void ShutdownMeshRendererGraphics(); - JULIET_API void ShutdownMeshRenderer(); - JULIET_API void LoadMeshesOnGPU(NonNullPtr cmdList); - JULIET_API void RenderMeshes(NonNullPtr cmdList, NonNullPtr pass, const Matrix& viewProjection); +JULIET_API void InitializeMeshRenderer(NonNullPtr assetArena, NonNullPtr instanceArena); +[[nodiscard]] JULIET_API bool InitializeMeshRendererGraphics(NonNullPtr device, NonNullPtr window); +JULIET_API void ShutdownMeshRendererGraphics(); +JULIET_API void ShutdownMeshRenderer(); +JULIET_API void LoadMeshesOnGPU(NonNullPtr cmdList); +JULIET_API void RenderMeshes(NonNullPtr cmdList, NonNullPtr pass, const Matrix& viewProjection); - // Lights - [[nodiscard]] JULIET_API LightID AddPointLight(const PointLight& light); - JULIET_API void SetPointLightPosition(LightID id, const Vector3& position); - JULIET_API void SetPointLightColor(LightID id, const Vector3& color); - JULIET_API void SetPointLightRadius(LightID id, float radius); - JULIET_API void SetPointLightIntensity(LightID id, float intensity); - JULIET_API void ClearPointLights(); - JULIET_API void SetGlobalLight(const Vector3& direction, const Vector3& color, float ambientIntensity); +// Lights +[[nodiscard]] JULIET_API LightID AddPointLight(const PointLight& light); +JULIET_API void SetPointLightPosition(LightID id, const Vector3& position); +JULIET_API void SetPointLightColor(LightID id, const Vector3& color); +JULIET_API void SetPointLightRadius(LightID id, float radius); +JULIET_API void SetPointLightIntensity(LightID id, float intensity); +JULIET_API void ClearPointLights(); +JULIET_API void SetGlobalLight(const Vector3& direction, const Vector3& color, float ambientIntensity); - // Assets & Instances - [[nodiscard]] JULIET_API MeshAssetID GetOrCreateMeshAsset(String name); - [[nodiscard]] JULIET_API MeshInstanceID CreateMeshInstance(MeshAssetID meshAsset, MaterialAssetID materialAsset, const Matrix& transform); - JULIET_API void SetMeshInstanceTransform(MeshInstanceID id, const Matrix& transform); +// Assets & Instances +[[nodiscard]] JULIET_API MeshAssetID GetOrCreateMeshAsset(String name); +[[nodiscard]] JULIET_API MeshInstanceID CreateMeshInstance(MeshAssetID meshAsset, MaterialAssetID materialAsset, const Matrix& transform); +JULIET_API void SetMeshInstanceTransform(MeshInstanceID id, const Matrix& transform); - // Primitives - JULIET_API MeshAssetID GetCubePrimitiveMeshAssetID(); - JULIET_API MeshAssetID GetQuadPrimitiveMeshAssetID(); - JULIET_API MeshAssetID GetSpherePrimitiveMeshAssetID(); +// Primitives +JULIET_API MeshAssetID GetCubePrimitiveMeshAssetID(); +JULIET_API MeshAssetID GetQuadPrimitiveMeshAssetID(); +JULIET_API MeshAssetID GetSpherePrimitiveMeshAssetID(); #if ALLOW_SHADER_HOT_RELOAD - JULIET_API void ReloadMeshRendererShaders(); +JULIET_API void ReloadMeshRendererShaders(); #endif -} // namespace Juliet diff --git a/Juliet/include/Graphics/PushConstants.h b/Juliet/include/Graphics/PushConstants.h index 1739fe8..beff445 100644 --- a/Juliet/include/Graphics/PushConstants.h +++ b/Juliet/include/Graphics/PushConstants.h @@ -1,32 +1,29 @@ -#pragma once +#pragma once #include #include #include -namespace Juliet +struct PushData { - struct PushData - { - Matrix ViewProjection; - uint32 MeshIndex; - uint32 TransformsBufferIndex; - uint32 BufferIndex; - uint32 TextureIndex; - uint32 VertexOffset; - uint32 LightBufferIndex; - uint32 ActiveLightCount; - float GlobalAmbientIntensity; + Matrix ViewProjection; + uint32 MeshIndex; + uint32 TransformsBufferIndex; + uint32 BufferIndex; + uint32 TextureIndex; + uint32 VertexOffset; + uint32 LightBufferIndex; + uint32 ActiveLightCount; + float GlobalAmbientIntensity; - Vector3 GlobalLightDirection; - uint32 Pad1; + Vector3 GlobalLightDirection; + uint32 Pad1; - Vector3 GlobalLightColor; - uint32 Pad2; - - float Scale[2]; - float Translate[2]; - - Vector4 MeshAlbedo; - }; -} // namespace Juliet + Vector3 GlobalLightColor; + uint32 Pad2; + + float Scale[2]; + float Translate[2]; + + Vector4 MeshAlbedo; +}; diff --git a/Juliet/include/Graphics/RenderPass.h b/Juliet/include/Graphics/RenderPass.h index 68da627..90e3c46 100644 --- a/Juliet/include/Graphics/RenderPass.h +++ b/Juliet/include/Graphics/RenderPass.h @@ -1,115 +1,112 @@ -#pragma once +#pragma once #include #include -namespace Juliet +enum struct LoadOperation : uint8 { - enum struct LoadOperation : uint8 + Load, // Load the texture from memory (preserve) + Clear, // Clear the texture + Ignore // Ignore the content of the texture (undefined) +}; + +enum struct StoreOperation : uint8 +{ + Store, // Store the result of the render pass into memory + Ignore, // Whatever is generated is ignored (undefined) + Resolve, // Resolve MipMaps into non mip map texture. Discard MipMap content + ResolveAndStore // Same but store the MipMap content to memory +}; + +struct ColorTargetInfo +{ + Texture* TargetTexture; + uint32 MipLevel; + union { - Load, // Load the texture from memory (preserve) - Clear, // Clear the texture - Ignore // Ignore the content of the texture (undefined) + uint32 DepthPlane; + uint32 LayerIndex; }; + bool CycleTexture; // Whether the texture should be cycled if already bound (and load operation != LOAD) - enum struct StoreOperation : uint8 - { - Store, // Store the result of the render pass into memory - Ignore, // Whatever is generated is ignored (undefined) - Resolve, // Resolve MipMaps into non mip map texture. Discard MipMap content - ResolveAndStore // Same but store the MipMap content to memory - }; + Texture* ResolveTexture; + uint32 ResolveMipLevel; + uint32 ResolveLayerIndex; + bool CycleResolveTexture; - struct ColorTargetInfo - { - Texture* TargetTexture; - uint32 MipLevel; - union - { - uint32 DepthPlane; - uint32 LayerIndex; - }; - bool CycleTexture; // Whether the texture should be cycled if already bound (and load operation != LOAD) + FColor ClearColor; + LoadOperation LoadOperation; + StoreOperation StoreOperation; +}; - Texture* ResolveTexture; - uint32 ResolveMipLevel; - uint32 ResolveLayerIndex; - bool CycleResolveTexture; +struct DepthStencilTargetInfo +{ + Texture* TargetTexture; + uint32 MipLevel; + uint32 LayerIndex; - FColor ClearColor; - LoadOperation LoadOperation; - StoreOperation StoreOperation; - }; - - struct DepthStencilTargetInfo - { - Texture* TargetTexture; - uint32 MipLevel; - uint32 LayerIndex; - - float ClearDepth; - uint8 ClearStencil; - LoadOperation LoadOperation; - StoreOperation StoreOperation; - }; + float ClearDepth; + uint8 ClearStencil; + LoadOperation LoadOperation; + StoreOperation StoreOperation; +}; - enum class BlendFactor : uint8 - { - Invalid, - Zero, - One, - Src_Color, - One_Minus_Src_Color, - Dst_Color, - One_Minus_Dst_Color, - Src_Alpha, - One_Minus_Src_Alpha, - Dst_Alpha, - One_Minus_Dst_Alpha, - Constant_Color, - One_MINUS_Constant_Color, - Src_Alpha_Saturate, // min(source alpha, 1 - destination alpha) - Count - }; + enum class BlendFactor : uint8 +{ + Invalid, + Zero, + One, + Src_Color, + One_Minus_Src_Color, + Dst_Color, + One_Minus_Dst_Color, + Src_Alpha, + One_Minus_Src_Alpha, + Dst_Alpha, + One_Minus_Dst_Alpha, + Constant_Color, + One_MINUS_Constant_Color, + Src_Alpha_Saturate, // min(source alpha, 1 - destination alpha) + Count +}; - enum class BlendOperation : uint8 - { - Invalid, - Add, // (source * source_factor) + (destination * destination_factor) - Subtract, // (source * source_factor) - (destination * destination_factor) - ReverseSubtract, // (destination * destination_factor) - (source * source_factor) - Min, // min(source, destination) - Max, // max(source, destination) - Count - }; +enum class BlendOperation : uint8 +{ + Invalid, + Add, // (source * source_factor) + (destination * destination_factor) + Subtract, // (source * source_factor) - (destination * destination_factor) + ReverseSubtract, // (destination * destination_factor) - (source * source_factor) + Min, // min(source, destination) + Max, // max(source, destination) + Count +}; - enum class ColorComponentFlags : uint8 - { - R = 1u << 0, - G = 1u << 1, - B = 1u << 2, - A = 1u << 3 - }; +enum class ColorComponentFlags : uint8 +{ + R = 1u << 0, + G = 1u << 1, + B = 1u << 2, + A = 1u << 3 +}; - struct ColorTargetBlendState - { - BlendFactor SourceColorBlendFactor; // The value to be multiplied by the source RGB value. - BlendFactor DestinationColorBlendFactor; // The value to be multiplied by the destination RGB value. - BlendOperation ColorBlendOperation; // The blend operation for the RGB components. - BlendFactor SourceAlphaBlendFactor; // The value to be multiplied by the source alpha. - BlendFactor DestinationAlphaBlendFactor; // The value to be multiplied by the destination alpha. - BlendOperation AlphaBlendOperation; // The blend operation for the alpha component. - ColorComponentFlags ColorWriteMask; // A bitmask specifying which of the RGBA components are enabled for writing. Writes to all channels if enable_color_write_mask is false. - bool EnableBlend : 1; // Whether blending is enabled for the color target. - bool EnableColorWriteMask : 1; // Whether the color write mask is enabled. - }; +struct ColorTargetBlendState +{ + BlendFactor SourceColorBlendFactor; // The value to be multiplied by the source RGB value. + BlendFactor DestinationColorBlendFactor; // The value to be multiplied by the destination RGB value. + BlendOperation ColorBlendOperation; // The blend operation for the RGB components. + BlendFactor SourceAlphaBlendFactor; // The value to be multiplied by the source alpha. + BlendFactor DestinationAlphaBlendFactor; // The value to be multiplied by the destination alpha. + BlendOperation AlphaBlendOperation; // The blend operation for the alpha component. + ColorComponentFlags ColorWriteMask; // A bitmask specifying which of the RGBA components are enabled for writing. Writes to all channels if enable_color_write_mask is false. + bool EnableBlend : 1; // Whether blending is enabled for the color target. + bool EnableColorWriteMask : 1; // Whether the color write mask is enabled. +}; - struct ColorTargetDescription - { - TextureFormat Format; - ColorTargetBlendState BlendState; - }; +struct ColorTargetDescription +{ + TextureFormat Format; + ColorTargetBlendState BlendState; +}; - // Opaque Type - struct RenderPass; -} // namespace Juliet +// Opaque Type +struct RenderPass; diff --git a/Juliet/include/Graphics/Shader.h b/Juliet/include/Graphics/Shader.h index 2fab3cc..a19f00f 100644 --- a/Juliet/include/Graphics/Shader.h +++ b/Juliet/include/Graphics/Shader.h @@ -1,23 +1,20 @@ -#pragma once +#pragma once #include -namespace Juliet +// Opaque type +struct Shader; + +enum class ShaderStage : uint8 { - // Opaque type - struct Shader; + Vertex, + Fragment, + Compute +}; - enum class ShaderStage : uint8 - { - Vertex, - Fragment, - Compute - }; +struct ShaderCreateInfo +{ + ShaderStage Stage; + String EntryPoint; +}; - struct ShaderCreateInfo - { - ShaderStage Stage; - String EntryPoint; - }; - -} // namespace Juliet diff --git a/Juliet/include/Graphics/SkyboxRenderer.h b/Juliet/include/Graphics/SkyboxRenderer.h index 210a196..cd2040d 100644 --- a/Juliet/include/Graphics/SkyboxRenderer.h +++ b/Juliet/include/Graphics/SkyboxRenderer.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include @@ -6,26 +6,23 @@ #include #include -namespace Juliet +struct RenderPass; +struct CommandList; +struct Window; +struct GraphicsPipeline; +struct GraphicsDevice; + +struct SkyboxRenderer { - struct RenderPass; - struct CommandList; - struct Window; - struct GraphicsPipeline; - struct GraphicsDevice; + GraphicsDevice* Device; + GraphicsPipeline* Pipeline; +}; - struct SkyboxRenderer - { - GraphicsDevice* Device; - GraphicsPipeline* Pipeline; - }; - - [[nodiscard]] JULIET_API bool InitializeSkyboxRenderer(NonNullPtr device, NonNullPtr window); - JULIET_API void ShutdownSkyboxRenderer(); - JULIET_API void RenderSkybox(NonNullPtr cmdList, NonNullPtr pass, const Matrix& viewProjection); +[[nodiscard]] JULIET_API bool InitializeSkyboxRenderer(NonNullPtr device, NonNullPtr window); +JULIET_API void ShutdownSkyboxRenderer(); +JULIET_API void RenderSkybox(NonNullPtr cmdList, NonNullPtr pass, const Matrix& viewProjection); #if ALLOW_SHADER_HOT_RELOAD - JULIET_API void ReloadSkyboxShaders(); +JULIET_API void ReloadSkyboxShaders(); #endif -} // namespace Juliet diff --git a/Juliet/include/Graphics/Texture.h b/Juliet/include/Graphics/Texture.h index 3ff0206..4b67c6c 100644 --- a/Juliet/include/Graphics/Texture.h +++ b/Juliet/include/Graphics/Texture.h @@ -1,183 +1,180 @@ -#pragma once +#pragma once -namespace Juliet +enum struct TextureFormat : uint8 { - enum struct TextureFormat : uint8 + Invalid, + + /* Unsigned Normalized Float Color Formats */ + A8_UNORM, + R8_UNORM, + R8G8_UNORM, + R8G8B8A8_UNORM, + R16_UNORM, + R16G16_UNORM, + R16G16B16A16_UNORM, + R10G10B10A2_UNORM, + B5G6R5_UNORM, + B5G5R5A1_UNORM, + B4G4R4A4_UNORM, + B8G8R8A8_UNORM, + /* Compressed Unsigned Normalized Float Color Formats */ + BC1_RGBA_UNORM, + BC2_RGBA_UNORM, + BC3_RGBA_UNORM, + BC4_R_UNORM, + BC5_RG_UNORM, + BC7_RGBA_UNORM, + /* Compressed Signed Float Color Formats */ + BC6H_RGB_FLOAT, + /* Compressed Unsigned Float Color Formats */ + BC6H_RGB_UFLOAT, + /* Signed Normalized Float Color Formats */ + R8_SNORM, + R8G8_SNORM, + R8G8B8A8_SNORM, + R16_SNORM, + R16G16_SNORM, + R16G16B16A16_SNORM, + /* Signed Float Color Formats */ + R16_FLOAT, + R16G16_FLOAT, + R16G16B16A16_FLOAT, + R32_FLOAT, + R32G32_FLOAT, + R32G32B32A32_FLOAT, + /* Unsigned Float Color Formats */ + R11G11B10_UFLOAT, + /* Unsigned Integer Color Formats */ + R8_UINT, + R8G8_UINT, + R8G8B8A8_UINT, + R16_UINT, + R16G16_UINT, + R16G16B16A16_UINT, + R32_UINT, + R32G32_UINT, + R32G32B32A32_UINT, + /* Signed Integer Color Formats */ + R8_INT, + R8G8_INT, + R8G8B8A8_INT, + R16_INT, + R16G16_INT, + R16G16B16A16_INT, + R32_INT, + R32G32_INT, + R32G32B32A32_INT, + /* SRGB Unsigned Normalized Color Formats */ + R8G8B8A8_UNORM_SRGB, + B8G8R8A8_UNORM_SRGB, + /* Compressed SRGB Unsigned Normalized Color Formats */ + BC1_RGBA_UNORM_SRGB, + BC2_RGBA_UNORM_SRGB, + BC3_RGBA_UNORM_SRGB, + BC7_RGBA_UNORM_SRGB, + /* Depth Formats */ + D16_UNORM, + D24_UNORM, + D32_FLOAT, + D24_UNORM_S8_UINT, + D32_FLOAT_S8_UINT, + /* Compressed ASTC Normalized Float Color Formats*/ + ASTC_4x4_UNORM, + ASTC_5x4_UNORM, + ASTC_5x5_UNORM, + ASTC_6x5_UNORM, + ASTC_6x6_UNORM, + ASTC_8x5_UNORM, + ASTC_8x6_UNORM, + ASTC_8x8_UNORM, + ASTC_10x5_UNORM, + ASTC_10x6_UNORM, + ASTC_10x8_UNORM, + ASTC_10x10_UNORM, + ASTC_12x10_UNORM, + ASTC_12x12_UNORM, + /* Compressed SRGB ASTC Normalized Float Color Formats*/ + ASTC_4x4_UNORM_SRGB, + ASTC_5x4_UNORM_SRGB, + ASTC_5x5_UNORM_SRGB, + ASTC_6x5_UNORM_SRGB, + ASTC_6x6_UNORM_SRGB, + ASTC_8x5_UNORM_SRGB, + ASTC_8x6_UNORM_SRGB, + ASTC_8x8_UNORM_SRGB, + ASTC_10x5_UNORM_SRGB, + ASTC_10x6_UNORM_SRGB, + ASTC_10x8_UNORM_SRGB, + ASTC_10x10_UNORM_SRGB, + ASTC_12x10_UNORM_SRGB, + ASTC_12x12_UNORM_SRGB, + /* Compressed ASTC Signed Float Color Formats*/ + ASTC_4x4_FLOAT, + ASTC_5x4_FLOAT, + ASTC_5x5_FLOAT, + ASTC_6x5_FLOAT, + ASTC_6x6_FLOAT, + ASTC_8x5_FLOAT, + ASTC_8x6_FLOAT, + ASTC_8x8_FLOAT, + ASTC_10x5_FLOAT, + ASTC_10x6_FLOAT, + ASTC_10x8_FLOAT, + ASTC_10x10_FLOAT, + ASTC_12x10_FLOAT, + ASTC_12x12_FLOAT, + + Count +}; + +enum struct TextureUsageFlag : uint8 +{ + None = 0, + Sampler = 1 << 0, // Textures supports sampling + ColorTarget = 1 << 1, // Texture is color render target + DepthStencilTarget = 1 << 2, // Texture is depth stencil target + GraphicsStorageRead = 1 << 3, // Support Storage read at graphics stage + ComputeStorageRead = 1 << 4, // Support Storage read at compute stage + ComputeStorageWrite = 1 << 5, // Support Storage Write at compute stage + ComputeStorageSimultaneousReadWrite = + 1 << 6, // Supports reads and writes in the same compute shader. Not equivalent to ComputeStorageRead | ComputeStorageWrite +}; + +enum struct TextureType : uint8 +{ + Texture_2D, + Texture_2DArray, + Texture_3D, + Texture_3DArray, + Texture_Cube, + Texture_CubeArray, +}; + +enum struct TextureSampleCount : uint8 +{ + One, + Two, + Four, + Eight, +}; + +// Create Information structs +struct TextureCreateInfo +{ + TextureType Type; + TextureFormat Format; + TextureUsageFlag Flags; + TextureSampleCount SampleCount; + + uint32 Width; + uint32 Height; + union { - Invalid, + uint32 LayerCount; + uint32 DepthPlane; + }; // LayerCount is used in 2d array textures and Depth for 3d textures + uint32 MipLevelCount; +}; - /* Unsigned Normalized Float Color Formats */ - A8_UNORM, - R8_UNORM, - R8G8_UNORM, - R8G8B8A8_UNORM, - R16_UNORM, - R16G16_UNORM, - R16G16B16A16_UNORM, - R10G10B10A2_UNORM, - B5G6R5_UNORM, - B5G5R5A1_UNORM, - B4G4R4A4_UNORM, - B8G8R8A8_UNORM, - /* Compressed Unsigned Normalized Float Color Formats */ - BC1_RGBA_UNORM, - BC2_RGBA_UNORM, - BC3_RGBA_UNORM, - BC4_R_UNORM, - BC5_RG_UNORM, - BC7_RGBA_UNORM, - /* Compressed Signed Float Color Formats */ - BC6H_RGB_FLOAT, - /* Compressed Unsigned Float Color Formats */ - BC6H_RGB_UFLOAT, - /* Signed Normalized Float Color Formats */ - R8_SNORM, - R8G8_SNORM, - R8G8B8A8_SNORM, - R16_SNORM, - R16G16_SNORM, - R16G16B16A16_SNORM, - /* Signed Float Color Formats */ - R16_FLOAT, - R16G16_FLOAT, - R16G16B16A16_FLOAT, - R32_FLOAT, - R32G32_FLOAT, - R32G32B32A32_FLOAT, - /* Unsigned Float Color Formats */ - R11G11B10_UFLOAT, - /* Unsigned Integer Color Formats */ - R8_UINT, - R8G8_UINT, - R8G8B8A8_UINT, - R16_UINT, - R16G16_UINT, - R16G16B16A16_UINT, - R32_UINT, - R32G32_UINT, - R32G32B32A32_UINT, - /* Signed Integer Color Formats */ - R8_INT, - R8G8_INT, - R8G8B8A8_INT, - R16_INT, - R16G16_INT, - R16G16B16A16_INT, - R32_INT, - R32G32_INT, - R32G32B32A32_INT, - /* SRGB Unsigned Normalized Color Formats */ - R8G8B8A8_UNORM_SRGB, - B8G8R8A8_UNORM_SRGB, - /* Compressed SRGB Unsigned Normalized Color Formats */ - BC1_RGBA_UNORM_SRGB, - BC2_RGBA_UNORM_SRGB, - BC3_RGBA_UNORM_SRGB, - BC7_RGBA_UNORM_SRGB, - /* Depth Formats */ - D16_UNORM, - D24_UNORM, - D32_FLOAT, - D24_UNORM_S8_UINT, - D32_FLOAT_S8_UINT, - /* Compressed ASTC Normalized Float Color Formats*/ - ASTC_4x4_UNORM, - ASTC_5x4_UNORM, - ASTC_5x5_UNORM, - ASTC_6x5_UNORM, - ASTC_6x6_UNORM, - ASTC_8x5_UNORM, - ASTC_8x6_UNORM, - ASTC_8x8_UNORM, - ASTC_10x5_UNORM, - ASTC_10x6_UNORM, - ASTC_10x8_UNORM, - ASTC_10x10_UNORM, - ASTC_12x10_UNORM, - ASTC_12x12_UNORM, - /* Compressed SRGB ASTC Normalized Float Color Formats*/ - ASTC_4x4_UNORM_SRGB, - ASTC_5x4_UNORM_SRGB, - ASTC_5x5_UNORM_SRGB, - ASTC_6x5_UNORM_SRGB, - ASTC_6x6_UNORM_SRGB, - ASTC_8x5_UNORM_SRGB, - ASTC_8x6_UNORM_SRGB, - ASTC_8x8_UNORM_SRGB, - ASTC_10x5_UNORM_SRGB, - ASTC_10x6_UNORM_SRGB, - ASTC_10x8_UNORM_SRGB, - ASTC_10x10_UNORM_SRGB, - ASTC_12x10_UNORM_SRGB, - ASTC_12x12_UNORM_SRGB, - /* Compressed ASTC Signed Float Color Formats*/ - ASTC_4x4_FLOAT, - ASTC_5x4_FLOAT, - ASTC_5x5_FLOAT, - ASTC_6x5_FLOAT, - ASTC_6x6_FLOAT, - ASTC_8x5_FLOAT, - ASTC_8x6_FLOAT, - ASTC_8x8_FLOAT, - ASTC_10x5_FLOAT, - ASTC_10x6_FLOAT, - ASTC_10x8_FLOAT, - ASTC_10x10_FLOAT, - ASTC_12x10_FLOAT, - ASTC_12x12_FLOAT, - - Count - }; - - enum struct TextureUsageFlag : uint8 - { - None = 0, - Sampler = 1 << 0, // Textures supports sampling - ColorTarget = 1 << 1, // Texture is color render target - DepthStencilTarget = 1 << 2, // Texture is depth stencil target - GraphicsStorageRead = 1 << 3, // Support Storage read at graphics stage - ComputeStorageRead = 1 << 4, // Support Storage read at compute stage - ComputeStorageWrite = 1 << 5, // Support Storage Write at compute stage - ComputeStorageSimultaneousReadWrite = - 1 << 6, // Supports reads and writes in the same compute shader. Not equivalent to ComputeStorageRead | ComputeStorageWrite - }; - - enum struct TextureType : uint8 - { - Texture_2D, - Texture_2DArray, - Texture_3D, - Texture_3DArray, - Texture_Cube, - Texture_CubeArray, - }; - - enum struct TextureSampleCount : uint8 - { - One, - Two, - Four, - Eight, - }; - - // Create Information structs - struct TextureCreateInfo - { - TextureType Type; - TextureFormat Format; - TextureUsageFlag Flags; - TextureSampleCount SampleCount; - - uint32 Width; - uint32 Height; - union - { - uint32 LayerCount; - uint32 DepthPlane; - }; // LayerCount is used in 2d array textures and Depth for 3d textures - uint32 MipLevelCount; - }; - - // Opaque Type - struct Texture; -} // namespace Juliet +// Opaque Type +struct Texture; diff --git a/Juliet/include/Graphics/VertexData.h b/Juliet/include/Graphics/VertexData.h index 5845e86..64bbcfc 100644 --- a/Juliet/include/Graphics/VertexData.h +++ b/Juliet/include/Graphics/VertexData.h @@ -1,13 +1,10 @@ -#pragma once +#pragma once -namespace Juliet +struct Vertex { - struct Vertex - { - float Position[3]; - float Normal[3]; - float Color[4]; - }; + float Position[3]; + float Normal[3]; + float Color[4]; +}; - using Index = uint16; -} // namespace Juliet +using Index = uint16; diff --git a/Juliet/src/Core/Application/ApplicationManager.cpp b/Juliet/src/Core/Application/ApplicationManager.cpp index 5bf23cc..ffbf20f 100644 --- a/Juliet/src/Core/Application/ApplicationManager.cpp +++ b/Juliet/src/Core/Application/ApplicationManager.cpp @@ -1,20 +1,17 @@ -#include +#include #include #include -namespace Juliet +void StartApplication(IApplication& app, JulietInit_Flags flags) { - void StartApplication(IApplication& app, JulietInit_Flags flags) - { - InitializeEngine(flags); + InitializeEngine(flags); - LoadApplication(app); + LoadApplication(app); - RunEngine(); + RunEngine(); - UnloadApplication(); + UnloadApplication(); - ShutdownEngine(); - } -} // namespace Juliet + ShutdownEngine(); +} diff --git a/Juliet/src/Core/Common/CoreUtils.cpp b/Juliet/src/Core/Common/CoreUtils.cpp index cecff81..24ad249 100644 --- a/Juliet/src/Core/Common/CoreUtils.cpp +++ b/Juliet/src/Core/Common/CoreUtils.cpp @@ -1,38 +1,35 @@ -#include +#include #include #include #include // For _com_error to decode HRESULTs #include // For __debugbreak -namespace Juliet +void JulietAssert(const char* expression, const char* message, std::source_location location, long handleResult) { - void JulietAssert(const char* expression, const char* message, std::source_location location, long handleResult) + Log(LogLevel::Error, LogCategory::Core, "--- ASSERTION FAILED ---"); + Log(LogLevel::Error, LogCategory::Core, "Expression: %s", expression); + Log(LogLevel::Error, LogCategory::Core, "Message: %s", message); + Log(LogLevel::Error, LogCategory::Core, "Location: %s(%u): %s", location.file_name(), location.line(), + location.function_name()); + + if (handleResult < 0) { - Log(LogLevel::Error, LogCategory::Core, "--- ASSERTION FAILED ---"); - Log(LogLevel::Error, LogCategory::Core, "Expression: %s", expression); - Log(LogLevel::Error, LogCategory::Core, "Message: %s", message); - Log(LogLevel::Error, LogCategory::Core, "Location: %s(%u): %s", location.file_name(), location.line(), - location.function_name()); - - if (handleResult < 0) - { - _com_error err(handleResult); - // Using %ls because ErrorMessage() returns a wide string (wchar_t*) - Log(LogLevel::Error, LogCategory::Graphics, "HRESULT: 0x%08X (%ls)", handleResult, err.ErrorMessage()); - } - - Log(LogLevel::Error, LogCategory::Core, "-------------------------"); - - JULIET_PLATFORM_BREAK(); + _com_error err(handleResult); + // Using %ls because ErrorMessage() returns a wide string (wchar_t*) + Log(LogLevel::Error, LogCategory::Graphics, "HRESULT: 0x%08X (%ls)", handleResult, err.ErrorMessage()); } - void Free(ByteBuffer& buffer) + Log(LogLevel::Error, LogCategory::Core, "-------------------------"); + + JULIET_PLATFORM_BREAK(); +} + +void Free(ByteBuffer& buffer) +{ + if (buffer.Data) { - if (buffer.Data) - { - Free(buffer.Data); - } - buffer = {}; + Free(buffer.Data); } -} // namespace Juliet + buffer = {}; +} diff --git a/Juliet/src/Core/Common/String.cpp b/Juliet/src/Core/Common/String.cpp index a7b9c17..c04d315 100644 --- a/Juliet/src/Core/Common/String.cpp +++ b/Juliet/src/Core/Common/String.cpp @@ -1,67 +1,500 @@ -#include +#include #include #include #include #include #include -namespace Juliet +namespace { - namespace + constexpr int32 kUnknown_UNICODE = 0xFFFD; + + struct { - constexpr int32 kUnknown_UNICODE = 0xFFFD; + String Name; + StringEncoding Format; + } Encodings[] = { + /* *INDENT-OFF* */ // clang-format off + { ConstString("ASCII"), StringEncoding::ASCII }, + { ConstString("US-ASCII"), StringEncoding::ASCII }, + { ConstString("8859-1"), StringEncoding::LATIN1 }, + { ConstString("ISO-8859-1"), StringEncoding::LATIN1 }, + #if defined(JULIET_WIN32) + { ConstString("WCHAR_T"), StringEncoding::UTF16 }, + #else + { ConstString("WCHAR_T"), StringEncoding::UCS4 }, + #endif + { ConstString("UTF8"), StringEncoding::UTF8 }, + { ConstString("UTF-8"), StringEncoding::UTF8 }, + { ConstString("UTF16"), StringEncoding::UTF16 }, + { ConstString("UTF-16"), StringEncoding::UTF16 }, + { ConstString("UTF32"), StringEncoding::UTF32 }, + { ConstString("UTF-32"), StringEncoding::UTF32 }, + { ConstString("UCS2"), StringEncoding::UCS2 }, + { ConstString("UCS-2"), StringEncoding::UCS2 }, + { ConstString("UCS-2-INTERNAL"), StringEncoding::UCS2 }, + { ConstString("UCS4"), StringEncoding::UCS4 }, + { ConstString("UCS-4"), StringEncoding::UCS4 }, + { ConstString("UCS-4-INTERNAL"), StringEncoding::UCS4 }, + /* *INDENT-ON* */ // clang-format on + }; - struct + // Returns the number of codepoint case folded (lowercase equivalent in the language) + // Takes an UTF-8 codepoint (uint32) and codefold it to up to 3 uint32 + // TODO Supports more than low ASCI :) + int8 CaseFoldUnicode(uint32 from, uint32* to) + { + if (from < 128) { - String Name; - StringEncoding Format; - } Encodings[] = { - /* *INDENT-OFF* */ // clang-format off - { ConstString("ASCII"), StringEncoding::ASCII }, - { ConstString("US-ASCII"), StringEncoding::ASCII }, - { ConstString("8859-1"), StringEncoding::LATIN1 }, - { ConstString("ISO-8859-1"), StringEncoding::LATIN1 }, - #if defined(JULIET_WIN32) - { ConstString("WCHAR_T"), StringEncoding::UTF16 }, - #else - { ConstString("WCHAR_T"), StringEncoding::UCS4 }, - #endif - { ConstString("UTF8"), StringEncoding::UTF8 }, - { ConstString("UTF-8"), StringEncoding::UTF8 }, - { ConstString("UTF16"), StringEncoding::UTF16 }, - { ConstString("UTF-16"), StringEncoding::UTF16 }, - { ConstString("UTF32"), StringEncoding::UTF32 }, - { ConstString("UTF-32"), StringEncoding::UTF32 }, - { ConstString("UCS2"), StringEncoding::UCS2 }, - { ConstString("UCS-2"), StringEncoding::UCS2 }, - { ConstString("UCS-2-INTERNAL"), StringEncoding::UCS2 }, - { ConstString("UCS4"), StringEncoding::UCS4 }, - { ConstString("UCS-4"), StringEncoding::UCS4 }, - { ConstString("UCS-4-INTERNAL"), StringEncoding::UCS4 }, - /* *INDENT-ON* */ // clang-format on - }; - - // Returns the number of codepoint case folded (lowercase equivalent in the language) - // Takes an UTF-8 codepoint (uint32) and codefold it to up to 3 uint32 - // TODO Supports more than low ASCI :) - int8 CaseFoldUnicode(uint32 from, uint32* to) - { - if (from < 128) + // low-ASCII, easy! + if ((from >= 'A') && (from <= 'Z')) { - // low-ASCII, easy! - if ((from >= 'A') && (from <= 'Z')) + *to = 'a' + (from - 'A'); + return 1; + } + } + *to = from; + return 1; + } +} // namespace + +// TODO: remove this as we convert to simple unicode decode / encode at the bottom +uint32 StepUTF8(String& inStr) +{ + // From rfc3629, the UTF-8 spec: + // https://www.ietf.org/rfc/rfc3629.txt + // + // Char. number range | UTF-8 octet sequence + // (hexadecimal) | (binary) + // --------------------+--------------------------------------------- + // 0000 0000-0000 007F | 0xxxxxxx + // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx + // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx + // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + // + // The function checks character validity and overlong (using too many bytes to encode the character) and return invalid utf8 char if detected. + + // If string is empty then it's done. + if (inStr.Size == 0) + { + return 0; + } + + auto str = reinterpret_cast(CStr(inStr)); + const uint32 octet = *str; + bool isOverlong = false; + bool isInvalid = false; + bool isUTF16Surrogate = false; + if (octet == 0) + { + return 0; + } + if ((octet & 0x80) == 0x0) // One byte code point: 0xxxxxxx + { + inStr.Str += 1; + inStr.Size -= 1; + return octet; + } + else if ((octet & 0xE0) == 0xC0) // Two bytes code point: 110xxxxx 10xxxxxx + { + const uint8 secondByte = str[1]; + if ((secondByte & 0xC0) == 0x80) // Make sure the trailing byte is correct + { + const uint32 result = ((octet & 0x1F) << 6) | (secondByte & 0x3F); + if (result >= 0x80) // If the result is smaller than 0x80 its an overlong! + { + inStr.Str += 2; + inStr.Size -= 1; + return result; + } + else + { + isOverlong = true; + } + } + else + { + isInvalid = true; + } + } + else if (((octet & 0xF0) == 0xE0)) // Three bytes code point: 1110xxxx 10xxxxxx 10xxxxxx + { + const uint8 secondByte = str[1]; + const uint8 thirdByte = str[2]; + if (((secondByte & 0xC0) == 0x80) && ((thirdByte & 0xC0) == 0x80)) // Make sure the trailing bytes are correct + { + const uint32 secondOctet = static_cast(secondByte & 0x3F) << 6; + const uint32 thirdOctet = static_cast(thirdByte & 0x3F); + const uint32 result = ((octet & 0x0F) << 12) | secondOctet | thirdOctet; + if (result >= 0x0800) // if the result is smaller its an overlong. + { + if ((result < 0xD800) || (result > 0xDFFF)) // If out of range its an UTF-16 surrogate { - *to = 'a' + (from - 'A'); - return 1; + inStr.Str += 3; + inStr.Size -= 1; + return result; + } + else + { + isUTF16Surrogate = true; } } - *to = from; + else + { + isOverlong = true; + } + } + else + { + isInvalid = true; + } + } + else if (((octet & 0xF8) == 0xF0)) + { // Four bytes code point: 11110xxxx 10xxxxxx 10xxxxxx 10xxxxxx + const uint8 secondByte = str[1]; + const uint8 thirdByte = str[2]; + const uint8 fourthByte = str[3]; + if (((secondByte & 0xC0) == 0x80) && ((thirdByte & 0xC0) == 0x80) && + ((fourthByte & 0xC0) == 0x80)) // // Make sure the trailing bytes are correct + { + const uint32 secondOctet = static_cast(secondByte & 0x1F) << 12; + const uint32 thirdOctet = static_cast(thirdByte & 0x3F) << 6; + const uint32 fourthOctet = static_cast(fourthByte & 0x3F); + const uint32 result = ((octet & 0x07) << 18) | secondOctet | thirdOctet | fourthOctet; + if (result >= 0x10000) // If smaller its an overlong + { + inStr.Str += 4; + inStr.Size -= 1; + return result; + } + else + { + isOverlong = true; + } + } + else + { + isInvalid = true; + } + } + LogError(LogCategory::Core, "StepUTF8: Non supported codepoint. IsOverlong: %s. IsInvalid %s. IsUTF16Surrogate %s", + isOverlong ? "true" : "false", isInvalid ? "true" : "false", isUTF16Surrogate ? "true" : "false"); + inStr.Str += 1; + return kInvalidUTF8; +} + +String FindString(String haystack, String needle) +{ + if (!IsValid(needle)) + { + return haystack; + } + + for (; IsValid(haystack); StepUTF8(haystack)) + { + String tempHaystack = haystack; + String testNeedle = needle; + + while (IsValid(tempHaystack) && IsValid(testNeedle)) + { + uint32 codepointHaystack = StepUTF8(tempHaystack); + uint32 codepointNeedle = StepUTF8(testNeedle); + if (codepointHaystack != codepointNeedle) + { + break; + } + } + + if (!IsValid(testNeedle)) + { + return haystack; + } + } + + return {}; +} + +int8 StringCompareCaseInsensitive(String str1, String str2) +{ + // TODO: Support UTF8. For now ASCII only. + uint32 left = 0; + uint32 right = 0; + while (true) + { + { + uint32 leftFolded[3]; + [[maybe_unused]] int8 num_folded = CaseFoldUnicode(StepUTF8(str1), leftFolded); + Assert(num_folded == 1); // Only one uint32 codepoint supported for now (low ascii) + left = leftFolded[0]; + } + { + uint32 rightFolded[3]; + [[maybe_unused]] int8 num_folded = CaseFoldUnicode(StepUTF8(str2), rightFolded); + Assert(num_folded == 1); // Only one uint32 codepoint supported for now (low ascii) + right = rightFolded[0]; + } + if (left < right) + { + return -1; + } + if (left > right) + { return 1; } - } // namespace + if (left == 0) + { + break; + } + } + return 0; +} - // TODO: remove this as we convert to simple unicode decode / encode at the bottom - uint32 StepUTF8(String& inStr) +bool ConvertString(StringEncoding from, StringEncoding to, String src, StringBuffer& dst, bool nullTerminate) +{ + Assert(IsValid(src)); + + const char* srcStr = src.Str; + char* dstStr = dst.Str; + size_t remainingCapacity = dst.Capacity; + + uint32 character = 0; + while (src.Size > 0) + { + // Decode in character + switch (from) + { + case StringEncoding::UTF8: // Uses RFC 3629 + { + auto p = reinterpret_cast(srcStr); + size_t left = 0; + bool overlong = false; + if (p[0] >= 0xF0) + { + if ((p[0] & 0xF8) != 0xF0) + { + character = kUnknown_UNICODE; + } + else + { + if (p[0] == 0xF0 && src.Size > 1 && (p[1] & 0xF0) == 0x80) + { + overlong = true; + } + character = static_cast(p[0] & 0x07); + left = 3; + } + } + else if (p[0] >= 0xE0) + { + if ((p[0] & 0xF0) != 0xE0) + { + character = kUnknown_UNICODE; + } + else + { + if (p[0] == 0xE0 && src.Size > 1 && (p[1] & 0xE0) == 0x80) + { + overlong = true; + } + character = static_cast(p[0] & 0x0F); + left = 2; + } + } + else if (p[0] >= 0xC0) + { + if ((p[0] & 0xE0) != 0xC0) + { + character = kUnknown_UNICODE; + } + else + { + if ((p[0] & 0xDE) == 0xC0) + { + overlong = true; + } + character = static_cast(p[0] & 0x1F); + left = 1; + } + } + else + { + if (p[0] & 0x80) + { + character = kUnknown_UNICODE; + } + else + { + character = static_cast(p[0]); + } + } + ++srcStr; + --src.Size; + if (src.Size < left) + { + Log(LogLevel::Error, LogCategory::Core, "ConvertString: Failed to convert string. Incomplete input sequence"); + return false; + } + while (left--) + { + ++p; + if ((p[0] & 0xC0) != 0x80) + { + character = kUnknown_UNICODE; + break; + } + character <<= 6; + character |= (p[0] & 0x3F); + ++srcStr; + --src.Size; + } + if (overlong) + { + character = kUnknown_UNICODE; + } + if ((character >= 0xD800 && character <= 0xDFFF) || (character == 0xFFFE || character == 0xFFFF) || + character > 0x10FFFF) + { + character = kUnknown_UNICODE; + } + break; + } + case StringEncoding::Unknown: Assert(false, "ConvertString: Invalid Source Format: Unknown"); break; + case StringEncoding::ASCII: + case StringEncoding::LATIN1: + case StringEncoding::UTF16: + case StringEncoding::UTF32: + case StringEncoding::UCS2: + case StringEncoding::UCS4: Assert(false, "ConvertString: Unsupported Source Format"); break; + } + + // Encode out character + switch (to) + { + case StringEncoding::UTF16: // RFC 2781 + { + auto p = reinterpret_cast(dstStr); + if (character > 0x10FFFF) + { + character = kUnknown_UNICODE; + } + if (character < 0x10000) + { + if (remainingCapacity < 2) + { + Log(LogLevel::Error, LogCategory::Core, "ConvertString: Destination buffer too short to fit UTF16"); + return false; + } + p[1] = static_cast(character >> 8); + p[0] = static_cast(character); + + dstStr += 2; + dst.Size += 1; + remainingCapacity -= 2; + } + else + { + if (remainingCapacity < 4) + { + Log(LogLevel::Error, LogCategory::Core, "ConvertString: Destination buffer too short to fit UTF16"); + return false; + } + character = character - 0x10000; + uint16 word1 = 0xD800U | static_cast((character >> 10) & 0x3FF); + uint16 word2 = 0xDC00U | static_cast(character & 0x3FF); + p[1] = static_cast(word1 >> 8); + p[0] = static_cast(word1); + p[3] = static_cast(word2 >> 8); + p[2] = static_cast(word2); + + dstStr += 4; + dst.Size += 1; + remainingCapacity -= 4; + } + break; + } + case StringEncoding::Unknown: Assert(false, "ConvertString: Invalid Source Format: Unknown"); break; + case StringEncoding::ASCII: + case StringEncoding::LATIN1: + case StringEncoding::UTF8: + case StringEncoding::UTF32: + case StringEncoding::UCS2: + case StringEncoding::UCS4: Assert(false, "ConvertString: Unsupported Destination Format"); break; + } + } + + if (nullTerminate) + { + switch (to) + { + case StringEncoding::UTF16: + { + if (remainingCapacity < 2) + { + Log(LogLevel::Error, LogCategory::Core, + "ConvertString: Destination buffer too short to add null terminator into UTF16 buffer"); + return false; + } + dstStr[0] = 0; + dstStr[1] = 0; + remainingCapacity -= 2; + break; + } + case StringEncoding::Unknown: Assert(false, "ConvertString: Invalid Source Format: Unknown"); break; + case StringEncoding::ASCII: + case StringEncoding::LATIN1: + case StringEncoding::UTF8: + case StringEncoding::UTF32: + case StringEncoding::UCS2: + case StringEncoding::UCS4: Assert(false, "ConvertString: Unsupported Destination Format"); break; + } + } + + return true; +} + +bool ConvertString(String from, String to, String src, StringBuffer& dst, bool nullTerminate) +{ + Assert(IsValid(from)); + Assert(IsValid(to)); + + // First find the encoding of the strings + auto sourceFormat = StringEncoding::Unknown; + auto destFormat = StringEncoding::Unknown; + for (auto& encoding : Encodings) + { + if (StringCompareCaseInsensitive(from, encoding.Name) == 0) + { + sourceFormat = encoding.Format; + if (destFormat != StringEncoding::Unknown) + { + break; + } + } + if (StringCompareCaseInsensitive(to, encoding.Name) == 0) + { + destFormat = encoding.Format; + if (sourceFormat != StringEncoding::Unknown) + { + break; + } + } + } + + if (sourceFormat == StringEncoding::Unknown || destFormat == StringEncoding::Unknown) + { + return false; + } + + return ConvertString(sourceFormat, destFormat, src, dst, nullTerminate); +} + +namespace +{ + uint8 utf8_class[32] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 5, + }; + + UnicodeDecode utf8_decode(uint8* str, size_t max) { // From rfc3629, the UTF-8 spec: // https://www.ietf.org/rfc/rfc3629.txt @@ -73,556 +506,120 @@ namespace Juliet // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - // - // The function checks character validity and overlong (using too many bytes to encode the character) and return invalid utf8 char if detected. - - // If string is empty then it's done. - if (inStr.Size == 0) + UnicodeDecode result = { 1, uint32Max }; + uint8 byte = str[0]; + uint8 byte_class = utf8_class[byte >> 3]; + switch (byte_class) { - return 0; - } - - auto str = reinterpret_cast(CStr(inStr)); - const uint32 octet = *str; - bool isOverlong = false; - bool isInvalid = false; - bool isUTF16Surrogate = false; - if (octet == 0) - { - return 0; - } - if ((octet & 0x80) == 0x0) // One byte code point: 0xxxxxxx - { - inStr.Str += 1; - inStr.Size -= 1; - return octet; - } - else if ((octet & 0xE0) == 0xC0) // Two bytes code point: 110xxxxx 10xxxxxx - { - const uint8 secondByte = str[1]; - if ((secondByte & 0xC0) == 0x80) // Make sure the trailing byte is correct + case 1: { - const uint32 result = ((octet & 0x1F) << 6) | (secondByte & 0x3F); - if (result >= 0x80) // If the result is smaller than 0x80 its an overlong! - { - inStr.Str += 2; - inStr.Size -= 1; - return result; - } - else - { - isOverlong = true; - } + result.Codepoint = byte; + break; } - else + case 2: { - isInvalid = true; - } - } - else if (((octet & 0xF0) == 0xE0)) // Three bytes code point: 1110xxxx 10xxxxxx 10xxxxxx - { - const uint8 secondByte = str[1]; - const uint8 thirdByte = str[2]; - if (((secondByte & 0xC0) == 0x80) && ((thirdByte & 0xC0) == 0x80)) // Make sure the trailing bytes are correct - { - const uint32 secondOctet = static_cast(secondByte & 0x3F) << 6; - const uint32 thirdOctet = static_cast(thirdByte & 0x3F); - const uint32 result = ((octet & 0x0F) << 12) | secondOctet | thirdOctet; - if (result >= 0x0800) // if the result is smaller its an overlong. + if (1 < max) { - if ((result < 0xD800) || (result > 0xDFFF)) // If out of range its an UTF-16 surrogate + uint8 next_byte = str[1]; + if (utf8_class[next_byte >> 3] == 0) { - inStr.Str += 3; - inStr.Size -= 1; - return result; - } - else - { - isUTF16Surrogate = true; + result.Codepoint = (byte & bitmask5) << 6; + result.Codepoint |= (next_byte & bitmask6); + result.Increment = 2; } } - else + break; + } + case 3: + { + if (2 < max) { - isOverlong = true; + uint8 next_byte[2] = { str[1], str[2] }; + if (utf8_class[next_byte[0] >> 3] == 0 && utf8_class[next_byte[1] >> 3] == 0) + { + result.Codepoint = (byte & bitmask4) << 12; + result.Codepoint |= ((next_byte[0] & bitmask6) << 6); + result.Codepoint |= (next_byte[1] & bitmask6); + result.Increment = 3; + } } + break; } - else + case 4: { - isInvalid = true; - } - } - else if (((octet & 0xF8) == 0xF0)) - { // Four bytes code point: 11110xxxx 10xxxxxx 10xxxxxx 10xxxxxx - const uint8 secondByte = str[1]; - const uint8 thirdByte = str[2]; - const uint8 fourthByte = str[3]; - if (((secondByte & 0xC0) == 0x80) && ((thirdByte & 0xC0) == 0x80) && - ((fourthByte & 0xC0) == 0x80)) // // Make sure the trailing bytes are correct - { - const uint32 secondOctet = static_cast(secondByte & 0x1F) << 12; - const uint32 thirdOctet = static_cast(thirdByte & 0x3F) << 6; - const uint32 fourthOctet = static_cast(fourthByte & 0x3F); - const uint32 result = ((octet & 0x07) << 18) | secondOctet | thirdOctet | fourthOctet; - if (result >= 0x10000) // If smaller its an overlong + if (3 < max) { - inStr.Str += 4; - inStr.Size -= 1; - return result; + uint8 next_byte[3] = { str[1], str[2], str[3] }; + if (utf8_class[next_byte[0] >> 3] == 0 && utf8_class[next_byte[1] >> 3] == 0 && + utf8_class[next_byte[2] >> 3] == 0) + { + result.Codepoint = (byte & bitmask3) << 18; + result.Codepoint |= ((next_byte[0] & bitmask6) << 12); + result.Codepoint |= ((next_byte[1] & bitmask6) << 6); + result.Codepoint |= (next_byte[2] & bitmask6); + result.Increment = 4; + } } - else - { - isOverlong = true; - } - } - else - { - isInvalid = true; - } - } - LogError(LogCategory::Core, "StepUTF8: Non supported codepoint. IsOverlong: %s. IsInvalid %s. IsUTF16Surrogate %s", - isOverlong ? "true" : "false", isInvalid ? "true" : "false", isUTF16Surrogate ? "true" : "false"); - inStr.Str += 1; - return kInvalidUTF8; - } - - String FindString(String haystack, String needle) - { - if (!IsValid(needle)) - { - return haystack; - } - - for (; IsValid(haystack); StepUTF8(haystack)) - { - String tempHaystack = haystack; - String testNeedle = needle; - - while (IsValid(tempHaystack) && IsValid(testNeedle)) - { - uint32 codepointHaystack = StepUTF8(tempHaystack); - uint32 codepointNeedle = StepUTF8(testNeedle); - if (codepointHaystack != codepointNeedle) - { - break; - } - } - - if (!IsValid(testNeedle)) - { - return haystack; - } - } - - return {}; - } - - int8 StringCompareCaseInsensitive(String str1, String str2) - { - // TODO: Support UTF8. For now ASCII only. - uint32 left = 0; - uint32 right = 0; - while (true) - { - { - uint32 leftFolded[3]; - [[maybe_unused]] int8 num_folded = CaseFoldUnicode(StepUTF8(str1), leftFolded); - Assert(num_folded == 1); // Only one uint32 codepoint supported for now (low ascii) - left = leftFolded[0]; - } - { - uint32 rightFolded[3]; - [[maybe_unused]] int8 num_folded = CaseFoldUnicode(StepUTF8(str2), rightFolded); - Assert(num_folded == 1); // Only one uint32 codepoint supported for now (low ascii) - right = rightFolded[0]; - } - if (left < right) - { - return -1; - } - if (left > right) - { - return 1; - } - if (left == 0) - { break; } } - return 0; - } - - bool ConvertString(StringEncoding from, StringEncoding to, String src, StringBuffer& dst, bool nullTerminate) - { - Assert(IsValid(src)); - - const char* srcStr = src.Str; - char* dstStr = dst.Str; - size_t remainingCapacity = dst.Capacity; - - uint32 character = 0; - while (src.Size > 0) - { - // Decode in character - switch (from) - { - case StringEncoding::UTF8: // Uses RFC 3629 - { - auto p = reinterpret_cast(srcStr); - size_t left = 0; - bool overlong = false; - if (p[0] >= 0xF0) - { - if ((p[0] & 0xF8) != 0xF0) - { - character = kUnknown_UNICODE; - } - else - { - if (p[0] == 0xF0 && src.Size > 1 && (p[1] & 0xF0) == 0x80) - { - overlong = true; - } - character = static_cast(p[0] & 0x07); - left = 3; - } - } - else if (p[0] >= 0xE0) - { - if ((p[0] & 0xF0) != 0xE0) - { - character = kUnknown_UNICODE; - } - else - { - if (p[0] == 0xE0 && src.Size > 1 && (p[1] & 0xE0) == 0x80) - { - overlong = true; - } - character = static_cast(p[0] & 0x0F); - left = 2; - } - } - else if (p[0] >= 0xC0) - { - if ((p[0] & 0xE0) != 0xC0) - { - character = kUnknown_UNICODE; - } - else - { - if ((p[0] & 0xDE) == 0xC0) - { - overlong = true; - } - character = static_cast(p[0] & 0x1F); - left = 1; - } - } - else - { - if (p[0] & 0x80) - { - character = kUnknown_UNICODE; - } - else - { - character = static_cast(p[0]); - } - } - ++srcStr; - --src.Size; - if (src.Size < left) - { - Log(LogLevel::Error, LogCategory::Core, "ConvertString: Failed to convert string. Incomplete input sequence"); - return false; - } - while (left--) - { - ++p; - if ((p[0] & 0xC0) != 0x80) - { - character = kUnknown_UNICODE; - break; - } - character <<= 6; - character |= (p[0] & 0x3F); - ++srcStr; - --src.Size; - } - if (overlong) - { - character = kUnknown_UNICODE; - } - if ((character >= 0xD800 && character <= 0xDFFF) || (character == 0xFFFE || character == 0xFFFF) || - character > 0x10FFFF) - { - character = kUnknown_UNICODE; - } - break; - } - case StringEncoding::Unknown: Assert(false, "ConvertString: Invalid Source Format: Unknown"); break; - case StringEncoding::ASCII: - case StringEncoding::LATIN1: - case StringEncoding::UTF16: - case StringEncoding::UTF32: - case StringEncoding::UCS2: - case StringEncoding::UCS4: Assert(false, "ConvertString: Unsupported Source Format"); break; - } - - // Encode out character - switch (to) - { - case StringEncoding::UTF16: // RFC 2781 - { - auto p = reinterpret_cast(dstStr); - if (character > 0x10FFFF) - { - character = kUnknown_UNICODE; - } - if (character < 0x10000) - { - if (remainingCapacity < 2) - { - Log(LogLevel::Error, LogCategory::Core, "ConvertString: Destination buffer too short to fit UTF16"); - return false; - } - p[1] = static_cast(character >> 8); - p[0] = static_cast(character); - - dstStr += 2; - dst.Size += 1; - remainingCapacity -= 2; - } - else - { - if (remainingCapacity < 4) - { - Log(LogLevel::Error, LogCategory::Core, "ConvertString: Destination buffer too short to fit UTF16"); - return false; - } - character = character - 0x10000; - uint16 word1 = 0xD800U | static_cast((character >> 10) & 0x3FF); - uint16 word2 = 0xDC00U | static_cast(character & 0x3FF); - p[1] = static_cast(word1 >> 8); - p[0] = static_cast(word1); - p[3] = static_cast(word2 >> 8); - p[2] = static_cast(word2); - - dstStr += 4; - dst.Size += 1; - remainingCapacity -= 4; - } - break; - } - case StringEncoding::Unknown: Assert(false, "ConvertString: Invalid Source Format: Unknown"); break; - case StringEncoding::ASCII: - case StringEncoding::LATIN1: - case StringEncoding::UTF8: - case StringEncoding::UTF32: - case StringEncoding::UCS2: - case StringEncoding::UCS4: Assert(false, "ConvertString: Unsupported Destination Format"); break; - } - } - - if (nullTerminate) - { - switch (to) - { - case StringEncoding::UTF16: - { - if (remainingCapacity < 2) - { - Log(LogLevel::Error, LogCategory::Core, - "ConvertString: Destination buffer too short to add null terminator into UTF16 buffer"); - return false; - } - dstStr[0] = 0; - dstStr[1] = 0; - remainingCapacity -= 2; - break; - } - case StringEncoding::Unknown: Assert(false, "ConvertString: Invalid Source Format: Unknown"); break; - case StringEncoding::ASCII: - case StringEncoding::LATIN1: - case StringEncoding::UTF8: - case StringEncoding::UTF32: - case StringEncoding::UCS2: - case StringEncoding::UCS4: Assert(false, "ConvertString: Unsupported Destination Format"); break; - } - } - - return true; - } - - bool ConvertString(String from, String to, String src, StringBuffer& dst, bool nullTerminate) - { - Assert(IsValid(from)); - Assert(IsValid(to)); - - // First find the encoding of the strings - auto sourceFormat = StringEncoding::Unknown; - auto destFormat = StringEncoding::Unknown; - for (auto& encoding : Encodings) - { - if (StringCompareCaseInsensitive(from, encoding.Name) == 0) - { - sourceFormat = encoding.Format; - if (destFormat != StringEncoding::Unknown) - { - break; - } - } - if (StringCompareCaseInsensitive(to, encoding.Name) == 0) - { - destFormat = encoding.Format; - if (sourceFormat != StringEncoding::Unknown) - { - break; - } - } - } - - if (sourceFormat == StringEncoding::Unknown || destFormat == StringEncoding::Unknown) - { - return false; - } - - return ConvertString(sourceFormat, destFormat, src, dst, nullTerminate); - } - - namespace - { - uint8 utf8_class[32] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 5, - }; - - UnicodeDecode utf8_decode(uint8* str, size_t max) - { - // From rfc3629, the UTF-8 spec: - // https://www.ietf.org/rfc/rfc3629.txt - // - // Char. number range | UTF-8 octet sequence - // (hexadecimal) | (binary) - // --------------------+--------------------------------------------- - // 0000 0000-0000 007F | 0xxxxxxx - // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx - // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx - // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - UnicodeDecode result = { 1, uint32Max }; - uint8 byte = str[0]; - uint8 byte_class = utf8_class[byte >> 3]; - switch (byte_class) - { - case 1: - { - result.Codepoint = byte; - break; - } - case 2: - { - if (1 < max) - { - uint8 next_byte = str[1]; - if (utf8_class[next_byte >> 3] == 0) - { - result.Codepoint = (byte & bitmask5) << 6; - result.Codepoint |= (next_byte & bitmask6); - result.Increment = 2; - } - } - break; - } - case 3: - { - if (2 < max) - { - uint8 next_byte[2] = { str[1], str[2] }; - if (utf8_class[next_byte[0] >> 3] == 0 && utf8_class[next_byte[1] >> 3] == 0) - { - result.Codepoint = (byte & bitmask4) << 12; - result.Codepoint |= ((next_byte[0] & bitmask6) << 6); - result.Codepoint |= (next_byte[1] & bitmask6); - result.Increment = 3; - } - } - break; - } - case 4: - { - if (3 < max) - { - uint8 next_byte[3] = { str[1], str[2], str[3] }; - if (utf8_class[next_byte[0] >> 3] == 0 && utf8_class[next_byte[1] >> 3] == 0 && - utf8_class[next_byte[2] >> 3] == 0) - { - result.Codepoint = (byte & bitmask3) << 18; - result.Codepoint |= ((next_byte[0] & bitmask6) << 12); - result.Codepoint |= ((next_byte[1] & bitmask6) << 6); - result.Codepoint |= (next_byte[2] & bitmask6); - result.Increment = 4; - } - } - break; - } - } - return result; - } - - uint32 utf16_encode(uint16* str, uint32 codepoint) - { - Assert(str); - uint32 increment = 1; - if (codepoint == uint32Max) - { - str[0] = '?'; - } - else if (codepoint < 0x10000) - { - str[0] = (uint16)codepoint; - } - else - { - uint32 var = codepoint - 0x10000; - str[0] = safe_cast_uint16(0xD800 + (var >> 10)); - str[1] = safe_cast_uint16(0xDC00 + (var & bitmask10)); - increment = 2; - } - return increment; - } - } // namespace - - String StringCopy(NonNullPtr arena, String str) - { - String result; - result.Size = str.Size; - result.Str = static_cast(ArenaPush(arena, str.Size + 1, alignof(char), true JULIET_DEBUG_PARAM("String"))); - MemCopy(result.Str, str.Str, str.Size); - result.Str[result.Size] = 0; return result; } - String16 str16_from_8(NonNullPtr arena, String8 in) + uint32 utf16_encode(uint16* str, uint32 codepoint) { - String16 result = {}; - if (in.Size > 0) + Assert(str); + uint32 increment = 1; + if (codepoint == uint32Max) { - size_t neededCapacity = in.Size * 2; - uint16* str = ArenaPushArray(arena, neededCapacity + 1); - uint8* inStr = (uint8*)in.Str; - uint8* inStrEnd = inStr + in.Size; - - UnicodeDecode consumed; - uint64 size = 0; - for (; inStr < inStrEnd; inStr += consumed.Increment) - { - consumed = utf8_decode(inStr, inStrEnd - inStr); - size += utf16_encode(str + size, consumed.Codepoint); - } - str[size] = 0; - ArenaPop(arena, (neededCapacity - size) * 2); - result = { str, size }; + str[0] = '?'; } - return result; + else if (codepoint < 0x10000) + { + str[0] = (uint16)codepoint; + } + else + { + uint32 var = codepoint - 0x10000; + str[0] = safe_cast_uint16(0xD800 + (var >> 10)); + str[1] = safe_cast_uint16(0xDC00 + (var & bitmask10)); + increment = 2; + } + return increment; } +} // namespace + +String StringCopy(NonNullPtr arena, String str) +{ + String result; + result.Size = str.Size; + result.Str = static_cast(ArenaPush(arena, str.Size + 1, alignof(char), true JULIET_DEBUG_PARAM("String"))); + MemCopy(result.Str, str.Str, str.Size); + result.Str[result.Size] = 0; + return result; +} + +String16 str16_from_8(NonNullPtr arena, String8 in) +{ + String16 result = {}; + if (in.Size > 0) + { + size_t neededCapacity = in.Size * 2; + uint16* str = ArenaPushArray(arena, neededCapacity + 1); + uint8* inStr = (uint8*)in.Str; + uint8* inStrEnd = inStr + in.Size; + + UnicodeDecode consumed; + uint64 size = 0; + for (; inStr < inStrEnd; inStr += consumed.Increment) + { + consumed = utf8_decode(inStr, inStrEnd - inStr); + size += utf16_encode(str + size, consumed.Codepoint); + } + str[size] = 0; + ArenaPop(arena, (neededCapacity - size) * 2); + result = { str, size }; + } + return result; +} -} // namespace Juliet diff --git a/Juliet/src/Core/Container/Vector.cpp b/Juliet/src/Core/Container/Vector.cpp index fd6b3a7..da54ccf 100644 --- a/Juliet/src/Core/Container/Vector.cpp +++ b/Juliet/src/Core/Container/Vector.cpp @@ -1,5 +1,2 @@ -#include +#include -namespace Juliet -{ -} diff --git a/Juliet/src/Core/HAL/Display/Display.cpp b/Juliet/src/Core/HAL/Display/Display.cpp index c201461..fde24cf 100644 --- a/Juliet/src/Core/HAL/Display/Display.cpp +++ b/Juliet/src/Core/HAL/Display/Display.cpp @@ -1,162 +1,159 @@ -#include +#include #include #include #include #include -namespace Juliet +namespace { - namespace + DisplayDevice* g_CurrentDisplayDevice = nullptr; + + void DestroyPlatformWindow(index_t windowIndex); +} // namespace + +namespace Internal::Display +{ + // TODO : IfDef new factories that are not compatible + constexpr DisplayDeviceFactory* Factories[] = { &Win32DisplayDeviceFactory, nullptr }; +} // namespace Internal::Display + +void InitializeDisplaySystem() +{ + Assert(!g_CurrentDisplayDevice); + + Arena* arena = ArenaAllocate({ .Name = "Display System" }); + + DisplayDevice* candidateDevice = nullptr; + DisplayDeviceFactory* candidateFactory = nullptr; + for (DisplayDeviceFactory* factory : Internal::Display::Factories) { - DisplayDevice* g_CurrentDisplayDevice = nullptr; - - void DestroyPlatformWindow(index_t windowIndex); - } // namespace - - namespace Internal::Display - { - // TODO : IfDef new factories that are not compatible - constexpr DisplayDeviceFactory* Factories[] = { &Win32DisplayDeviceFactory, nullptr }; - } // namespace Internal::Display - - void InitializeDisplaySystem() - { - Assert(!g_CurrentDisplayDevice); - - Arena* arena = ArenaAllocate({ .Name = "Display System" }); - - DisplayDevice* candidateDevice = nullptr; - DisplayDeviceFactory* candidateFactory = nullptr; - for (DisplayDeviceFactory* factory : Internal::Display::Factories) + if (factory) { - if (factory) + candidateDevice = factory->CreateDevice(arena); + if (candidateDevice) { - candidateDevice = factory->CreateDevice(arena); - if (candidateDevice) - { - candidateFactory = factory; - break; - } - } - } - - // TODO : handle error instead of crashing - Assert(candidateDevice); - - g_CurrentDisplayDevice = candidateDevice; - g_CurrentDisplayDevice->Arena = arena; - g_CurrentDisplayDevice->Name = candidateFactory->Name; - - if (!g_CurrentDisplayDevice->Initialize(g_CurrentDisplayDevice)) - { - ShutdownDisplaySystem(); - } - } - - void ShutdownDisplaySystem() - { - if (!g_CurrentDisplayDevice) - { - return; - } - - // Destroy all Windows that are still alive - for (index_t idx = g_CurrentDisplayDevice->Windows.Size(); idx-- > 0;) - { - DestroyPlatformWindow(idx); - } - - g_CurrentDisplayDevice->Shutdown(g_CurrentDisplayDevice); - // Free anything that was freed by the shutdown and then free the display - // no op for now - g_CurrentDisplayDevice->Free(g_CurrentDisplayDevice); - - ArenaRelease(g_CurrentDisplayDevice->Arena); - g_CurrentDisplayDevice = nullptr; - } - - Window* CreatePlatformWindow(const char* title, uint16 width, uint16 height, int /*flags*/ /* = 0 unused */) - { - Assert(g_CurrentDisplayDevice->CreatePlatformWindow); - - Window window = {}; - window.Arena = ArenaAllocate({ .Name = "Window" }); - window.Width = width; - window.Height = height; - - window.Title = StringCopy(window.Arena, WrapString(title)); - - g_CurrentDisplayDevice->Windows.PushBack(window); - - auto* pWindow = g_CurrentDisplayDevice->Windows.Last(); - if (!g_CurrentDisplayDevice->CreatePlatformWindow(g_CurrentDisplayDevice, pWindow)) - { - ArenaRelease(window.Arena); - return nullptr; - } - - // TODO : make SHOW optional on creation with a flag - g_CurrentDisplayDevice->ShowWindow(g_CurrentDisplayDevice, pWindow); - - return pWindow; - } - - namespace - { - void DestroyPlatformWindow(index_t windowIndex) - { - VectorArena& windows = g_CurrentDisplayDevice->Windows; - Window* window = &windows[windowIndex]; - - HideWindow(window); - - g_CurrentDisplayDevice->DestroyPlatformWindow(g_CurrentDisplayDevice, window); - - ArenaClear(window->Arena); - ArenaRelease(window->Arena); - - windows.RemoveAtFast(windowIndex); - } - } // namespace - - void DestroyPlatformWindow(NonNullPtr window) - { - // Find and destroy - VectorArena& windows = g_CurrentDisplayDevice->Windows; - for (index_t idx = windows.Size(); idx-- > 0;) - { - Window& windowRef = windows[idx]; - if (windowRef.ID == window->ID) - { - DestroyPlatformWindow(idx); + candidateFactory = factory; break; } } } - void ShowWindow(NonNullPtr window) + // TODO : handle error instead of crashing + Assert(candidateDevice); + + g_CurrentDisplayDevice = candidateDevice; + g_CurrentDisplayDevice->Arena = arena; + g_CurrentDisplayDevice->Name = candidateFactory->Name; + + if (!g_CurrentDisplayDevice->Initialize(g_CurrentDisplayDevice)) { - g_CurrentDisplayDevice->ShowWindow(g_CurrentDisplayDevice, window); + ShutdownDisplaySystem(); + } +} + +void ShutdownDisplaySystem() +{ + if (!g_CurrentDisplayDevice) + { + return; } - void HideWindow(NonNullPtr window) + // Destroy all Windows that are still alive + for (index_t idx = g_CurrentDisplayDevice->Windows.Size(); idx-- > 0;) { - g_CurrentDisplayDevice->HideWindow(g_CurrentDisplayDevice, window); + DestroyPlatformWindow(idx); } - WindowID GetWindowID(NonNullPtr window) + g_CurrentDisplayDevice->Shutdown(g_CurrentDisplayDevice); + // Free anything that was freed by the shutdown and then free the display + // no op for now + g_CurrentDisplayDevice->Free(g_CurrentDisplayDevice); + + ArenaRelease(g_CurrentDisplayDevice->Arena); + g_CurrentDisplayDevice = nullptr; +} + +Window* CreatePlatformWindow(const char* title, uint16 width, uint16 height, int /*flags*/ /* = 0 unused */) +{ + Assert(g_CurrentDisplayDevice->CreatePlatformWindow); + + Window window = {}; + window.Arena = ArenaAllocate({ .Name = "Window" }); + window.Width = width; + window.Height = height; + + window.Title = StringCopy(window.Arena, WrapString(title)); + + g_CurrentDisplayDevice->Windows.PushBack(window); + + auto* pWindow = g_CurrentDisplayDevice->Windows.Last(); + if (!g_CurrentDisplayDevice->CreatePlatformWindow(g_CurrentDisplayDevice, pWindow)) { - return window->ID; + ArenaRelease(window.Arena); + return nullptr; } - void SetWindowTitle(NonNullPtr window, String title) - { - g_CurrentDisplayDevice->SetWindowTitle(g_CurrentDisplayDevice, window, title); - } + // TODO : make SHOW optional on creation with a flag + g_CurrentDisplayDevice->ShowWindow(g_CurrentDisplayDevice, pWindow); - // Display Device Utils. Not exposed in the API - DisplayDevice* GetDisplayDevice() + return pWindow; +} + +namespace +{ + void DestroyPlatformWindow(index_t windowIndex) { - return g_CurrentDisplayDevice; + VectorArena& windows = g_CurrentDisplayDevice->Windows; + Window* window = &windows[windowIndex]; + + HideWindow(window); + + g_CurrentDisplayDevice->DestroyPlatformWindow(g_CurrentDisplayDevice, window); + + ArenaClear(window->Arena); + ArenaRelease(window->Arena); + + windows.RemoveAtFast(windowIndex); } -} // namespace Juliet +} // namespace + +void DestroyPlatformWindow(NonNullPtr window) +{ + // Find and destroy + VectorArena& windows = g_CurrentDisplayDevice->Windows; + for (index_t idx = windows.Size(); idx-- > 0;) + { + Window& windowRef = windows[idx]; + if (windowRef.ID == window->ID) + { + DestroyPlatformWindow(idx); + break; + } + } +} + +void ShowWindow(NonNullPtr window) +{ + g_CurrentDisplayDevice->ShowWindow(g_CurrentDisplayDevice, window); +} + +void HideWindow(NonNullPtr window) +{ + g_CurrentDisplayDevice->HideWindow(g_CurrentDisplayDevice, window); +} + +WindowID GetWindowID(NonNullPtr window) +{ + return window->ID; +} + +void SetWindowTitle(NonNullPtr window, String title) +{ + g_CurrentDisplayDevice->SetWindowTitle(g_CurrentDisplayDevice, window, title); +} + +// Display Device Utils. Not exposed in the API +DisplayDevice* GetDisplayDevice() +{ + return g_CurrentDisplayDevice; +} diff --git a/Juliet/src/Core/HAL/Display/DisplayDevice.h b/Juliet/src/Core/HAL/Display/DisplayDevice.h index 4a4c6fe..469d015 100644 --- a/Juliet/src/Core/HAL/Display/DisplayDevice.h +++ b/Juliet/src/Core/HAL/Display/DisplayDevice.h @@ -1,47 +1,44 @@ -#pragma once +#pragma once #include #include #include -namespace Juliet +// Driver to the display device. +// Functions ptr will be set by the chosen factory +// Acts as a singleton after Initialize has been called and is freed in Shutdown. +struct DisplayDevice { - // Driver to the display device. - // Functions ptr will be set by the chosen factory - // Acts as a singleton after Initialize has been called and is freed in Shutdown. - struct DisplayDevice - { - Arena* Arena; + Arena* Arena; - const char* Name = "Unknown"; + const char* Name = "Unknown"; - // Initialize all subsystems needed for the device to works - bool (*Initialize)(NonNullPtr self); - void (*Shutdown)(NonNullPtr self); - void (*Free)(NonNullPtr self); + // Initialize all subsystems needed for the device to works + bool (*Initialize)(NonNullPtr self); + void (*Shutdown)(NonNullPtr self); + void (*Free)(NonNullPtr self); - // Window management - bool (*CreatePlatformWindow)(NonNullPtr self, NonNullPtr window); - void (*DestroyPlatformWindow)(NonNullPtr self, NonNullPtr window); - void (*ShowWindow)(NonNullPtr self, NonNullPtr window); - void (*HideWindow)(NonNullPtr self, NonNullPtr window); - void (*SetWindowTitle)(NonNullPtr self, NonNullPtr window, String title); + // Window management + bool (*CreatePlatformWindow)(NonNullPtr self, NonNullPtr window); + void (*DestroyPlatformWindow)(NonNullPtr self, NonNullPtr window); + void (*ShowWindow)(NonNullPtr self, NonNullPtr window); + void (*HideWindow)(NonNullPtr self, NonNullPtr window); + void (*SetWindowTitle)(NonNullPtr self, NonNullPtr window, String title); - // Events - void (*PumpEvents)(NonNullPtr self); + // Events + void (*PumpEvents)(NonNullPtr self); - VectorArena Windows; - }; + VectorArena Windows; +}; - struct DisplayDeviceFactory - { - const char* Name = "Unknown"; - DisplayDevice* (*CreateDevice)(Arena* arena); - }; +struct DisplayDeviceFactory +{ + const char* Name = "Unknown"; + DisplayDevice* (*CreateDevice)(Arena* arena); +}; - // TODO : Support more platforms - extern DisplayDeviceFactory Win32DisplayDeviceFactory; +// TODO : Support more platforms +extern DisplayDeviceFactory Win32DisplayDeviceFactory; - // Utils - extern DisplayDevice* GetDisplayDevice(); -} // namespace Juliet +// Utils +extern DisplayDevice* GetDisplayDevice(); diff --git a/Juliet/src/Core/HAL/Display/Display_cpp.h b/Juliet/src/Core/HAL/Display/Display_cpp.h index 0256c5b..98268fa 100644 --- a/Juliet/src/Core/HAL/Display/Display_cpp.h +++ b/Juliet/src/Core/HAL/Display/Display_cpp.h @@ -1,7 +1,4 @@ -#pragma once +#pragma once -namespace Juliet -{ - void InitializeDisplaySystem(); - void ShutdownDisplaySystem(); -} // namespace Juliet +void InitializeDisplaySystem(); +void ShutdownDisplaySystem(); diff --git a/Juliet/src/Core/HAL/Display/Win32/Win32DisplayDevice.cpp b/Juliet/src/Core/HAL/Display/Win32/Win32DisplayDevice.cpp index 8f00302..b29b2a4 100644 --- a/Juliet/src/Core/HAL/Display/Win32/Win32DisplayDevice.cpp +++ b/Juliet/src/Core/HAL/Display/Win32/Win32DisplayDevice.cpp @@ -1,8 +1,8 @@ -#include +#include #include #include -namespace Juliet::Win32 +namespace Win32 { namespace { @@ -43,10 +43,7 @@ namespace Juliet::Win32 } } // namespace -} // namespace Juliet::Win32 +} // namespace Win32 // Factory cannot be in an anonymous/unknown namespace -namespace Juliet -{ - DisplayDeviceFactory Win32DisplayDeviceFactory = { .Name = "Win32", .CreateDevice = Win32::CreateDevice }; -} +DisplayDeviceFactory Win32DisplayDeviceFactory = { .Name = "Win32", .CreateDevice = Win32::CreateDevice }; diff --git a/Juliet/src/Core/HAL/Display/Win32/Win32DisplayEvent.cpp b/Juliet/src/Core/HAL/Display/Win32/Win32DisplayEvent.cpp index 5a9815b..77666c9 100644 --- a/Juliet/src/Core/HAL/Display/Win32/Win32DisplayEvent.cpp +++ b/Juliet/src/Core/HAL/Display/Win32/Win32DisplayEvent.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -20,7 +20,7 @@ extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); #endif -namespace Juliet::Win32 +namespace Win32 { namespace { @@ -276,4 +276,4 @@ namespace Juliet::Win32 return CallWindowProcA(DefWindowProcA, handle, message, wParam, lParam); } -} // namespace Juliet::Win32 +} // namespace Win32 diff --git a/Juliet/src/Core/HAL/Display/Win32/Win32DisplayEvent.h b/Juliet/src/Core/HAL/Display/Win32/Win32DisplayEvent.h index a6af2e6..65b8af6 100644 --- a/Juliet/src/Core/HAL/Display/Win32/Win32DisplayEvent.h +++ b/Juliet/src/Core/HAL/Display/Win32/Win32DisplayEvent.h @@ -1,15 +1,12 @@ -#pragma once +#pragma once #include #include -namespace Juliet -{ - struct DisplayDevice; -} +struct DisplayDevice; -namespace Juliet::Win32 +namespace Win32 { extern void PumpEvents(NonNullPtr self); extern LRESULT CALLBACK Win32MainWindowCallback(HWND Handle, UINT Message, WPARAM WParam, LPARAM LParam); -} // namespace Juliet::Win32 +} // namespace Win32 diff --git a/Juliet/src/Core/HAL/Display/Win32/Win32Window.cpp b/Juliet/src/Core/HAL/Display/Win32/Win32Window.cpp index 0f3a429..80c9d92 100644 --- a/Juliet/src/Core/HAL/Display/Win32/Win32Window.cpp +++ b/Juliet/src/Core/HAL/Display/Win32/Win32Window.cpp @@ -1,10 +1,10 @@ -#include +#include #include #include #include #include -namespace Juliet::Win32 +namespace Win32 { namespace { @@ -101,4 +101,4 @@ namespace Juliet::Win32 auto& win32State = static_cast(*window->State); SetWindowTextA(win32State.Handle, CStr(title)); } -} // namespace Juliet::Win32 +} // namespace Win32 diff --git a/Juliet/src/Core/HAL/Display/Win32/Win32Window.h b/Juliet/src/Core/HAL/Display/Win32/Win32Window.h index 807d334..88d4d6b 100644 --- a/Juliet/src/Core/HAL/Display/Win32/Win32Window.h +++ b/Juliet/src/Core/HAL/Display/Win32/Win32Window.h @@ -1,16 +1,13 @@ -#pragma once +#pragma once #include #include #include -namespace Juliet -{ - struct DisplayDevice; - struct Window; -} // namespace Juliet +struct DisplayDevice; +struct Window; -namespace Juliet::Win32 +namespace Win32 { // TODO : Evaluate if its worth the burden of casting to Window32State all the time struct Window32State : WindowState @@ -26,4 +23,4 @@ namespace Juliet::Win32 extern void ShowWindow(NonNullPtr self, NonNullPtr window); extern void HideWindow(NonNullPtr self, NonNullPtr window); extern void SetWindowTitle(NonNullPtr self, NonNullPtr window, String title); -} // namespace Juliet::Win32 +} // namespace Win32 diff --git a/Juliet/src/Core/HAL/Display/Window.h b/Juliet/src/Core/HAL/Display/Window.h index 32faa1e..e7fe30d 100644 --- a/Juliet/src/Core/HAL/Display/Window.h +++ b/Juliet/src/Core/HAL/Display/Window.h @@ -1,24 +1,21 @@ -#pragma once +#pragma once #include #include -namespace Juliet +struct Window; +struct WindowState { - struct Window; - struct WindowState - { - Window* Window; - }; + Window* Window; +}; - struct Window - { - WindowID ID; - WindowState* State; - Arena* Arena; +struct Window +{ + WindowID ID; + WindowState* State; + Arena* Arena; - int32 Width; - int32 Height; - String Title; - }; -} // namespace Juliet + int32 Width; + int32 Height; + String Title; +}; diff --git a/Juliet/src/Core/HAL/DynLib/Win32/DynamicLibrary.cpp b/Juliet/src/Core/HAL/DynLib/Win32/DynamicLibrary.cpp index 57c40e9..6bd189e 100644 --- a/Juliet/src/Core/HAL/DynLib/Win32/DynamicLibrary.cpp +++ b/Juliet/src/Core/HAL/DynLib/Win32/DynamicLibrary.cpp @@ -1,44 +1,41 @@ -#include +#include #include #include #include -namespace Juliet +DynamicLibrary* LoadDynamicLibrary(const char* filename) { - DynamicLibrary* LoadDynamicLibrary(const char* filename) + if (!filename) { - if (!filename) - { - Log(LogLevel::Error, LogCategory::Core, "Library filename is invalid (empty)"); - return nullptr; - } - - HMODULE handle = LoadLibraryA(filename); - - // Generate an error message if all loads failed - if (!handle) - { - Log(LogLevel::Error, LogCategory::Core, "Failed loading %s", filename); - return nullptr; - } - return reinterpret_cast(handle); + Log(LogLevel::Error, LogCategory::Core, "Library filename is invalid (empty)"); + return nullptr; } - FunctionPtr LoadFunction(NonNullPtr lib, const char* functionName) + HMODULE handle = LoadLibraryA(filename); + + // Generate an error message if all loads failed + if (!handle) { + Log(LogLevel::Error, LogCategory::Core, "Failed loading %s", filename); + return nullptr; + } + return reinterpret_cast(handle); +} + +FunctionPtr LoadFunction(NonNullPtr lib, const char* functionName) +{ #pragma warning(push) #pragma warning(disable: 4191) // Disable "unsafe conversion from FARPROC" - auto function = reinterpret_cast(GetProcAddress(reinterpret_cast(lib.Get()), functionName)); - if (!function) - { - Log(LogLevel::Error, LogCategory::Core, "Failed loading %s", functionName); - } - return function; -#pragma warning(pop) - } - - void UnloadDynamicLibrary(NonNullPtr lib) + auto function = reinterpret_cast(GetProcAddress(reinterpret_cast(lib.Get()), functionName)); + if (!function) { - FreeLibrary(reinterpret_cast(lib.Get())); + Log(LogLevel::Error, LogCategory::Core, "Failed loading %s", functionName); } -} // namespace Juliet + return function; +#pragma warning(pop) +} + +void UnloadDynamicLibrary(NonNullPtr lib) +{ + FreeLibrary(reinterpret_cast(lib.Get())); +} diff --git a/Juliet/src/Core/HAL/Event/Keyboard.cpp b/Juliet/src/Core/HAL/Event/Keyboard.cpp index 1745b77..e2eb1fd 100644 --- a/Juliet/src/Core/HAL/Event/Keyboard.cpp +++ b/Juliet/src/Core/HAL/Event/Keyboard.cpp @@ -1,165 +1,162 @@ -#include +#include #include #include #include -namespace Juliet +constexpr KeyboardID kGlobalKeyboardID = 0; + +namespace { - constexpr KeyboardID kGlobalKeyboardID = 0; - - namespace + struct KeyboardState { - struct KeyboardState + KeyState KeyState[ToUnderlying(ScanCode::Count)]; + KeyMod KeyModState; + } KeyboardState; + + bool SendKeyboardKey_Internal(uint64 timestamp, KeyboardID /*ID*/, Key key, KeyPosition keyPosition) + { + Assert(key.KeyCode == KeyCode::Unknown); // At this point Keycode is not yet extracted + + auto& keyboardState = KeyboardState; // Needed because MSVC debugger ignores variable in anonymouse namespace + + auto type = EventType::None; + const bool isKeyDown = keyPosition == KeyPosition::Down; + if (isKeyDown) { - KeyState KeyState[ToUnderlying(ScanCode::Count)]; - KeyMod KeyModState; - } KeyboardState; - - bool SendKeyboardKey_Internal(uint64 timestamp, KeyboardID /*ID*/, Key key, KeyPosition keyPosition) + type = EventType::Key_Down; + } + else { - Assert(key.KeyCode == KeyCode::Unknown); // At this point Keycode is not yet extracted + type = EventType::Key_Up; + } - auto& keyboardState = KeyboardState; // Needed because MSVC debugger ignores variable in anonymouse namespace + bool isKeyRepeat = false; + if (key.ScanCode > ScanCode::Unknown && key.ScanCode < ScanCode::Count) + { + auto& currentKeyState = keyboardState.KeyState[ToUnderlying(key.ScanCode)]; - auto type = EventType::None; - const bool isKeyDown = keyPosition == KeyPosition::Down; + // If state didn't change, this is a key repeat if (isKeyDown) { - type = EventType::Key_Down; + if (currentKeyState.Position == KeyPosition::Down) + { + isKeyRepeat = true; + } } else { - type = EventType::Key_Up; - } - - bool isKeyRepeat = false; - if (key.ScanCode > ScanCode::Unknown && key.ScanCode < ScanCode::Count) - { - auto& currentKeyState = keyboardState.KeyState[ToUnderlying(key.ScanCode)]; - - // If state didn't change, this is a key repeat - if (isKeyDown) + if (currentKeyState.Position == KeyPosition::Up) { - if (currentKeyState.Position == KeyPosition::Down) - { - isKeyRepeat = true; - } + return false; } - else - { - if (currentKeyState.Position == KeyPosition::Up) - { - return false; - } - } - - currentKeyState.Position = keyPosition; - key.KeyCode = GetKeyCodeFromScanCode(key.ScanCode, keyboardState.KeyModState); - } - else if (key.Raw == 0) - { - return false; } - if (!isKeyRepeat) - { - KeyMod newModifier = {}; + currentKeyState.Position = keyPosition; + key.KeyCode = GetKeyCodeFromScanCode(key.ScanCode, keyboardState.KeyModState); + } + else if (key.Raw == 0) + { + return false; + } + if (!isKeyRepeat) + { + KeyMod newModifier = {}; + + switch (key.KeyCode) + { + case KeyCode::LeftControl: newModifier = KeyMod::LeftControl; break; + case KeyCode::RightControl: newModifier = KeyMod::RightControl; break; + case KeyCode::LeftShift: newModifier = KeyMod::LeftShift; break; + case KeyCode::RightShift: newModifier = KeyMod::RightShift; break; + case KeyCode::LeftAlt: newModifier = KeyMod::LeftAlt; break; + case KeyCode::RightAlt: newModifier = KeyMod::RightAlt; break; + case KeyCode::LeftOSCommand: newModifier = KeyMod::LeftOSCommand; break; + case KeyCode::RightOSCommand: newModifier = KeyMod::RightOSCommand; break; + default: newModifier = KeyMod::None; break; + } + if (type == EventType::Key_Down) + { switch (key.KeyCode) { - case KeyCode::LeftControl: newModifier = KeyMod::LeftControl; break; - case KeyCode::RightControl: newModifier = KeyMod::RightControl; break; - case KeyCode::LeftShift: newModifier = KeyMod::LeftShift; break; - case KeyCode::RightShift: newModifier = KeyMod::RightShift; break; - case KeyCode::LeftAlt: newModifier = KeyMod::LeftAlt; break; - case KeyCode::RightAlt: newModifier = KeyMod::RightAlt; break; - case KeyCode::LeftOSCommand: newModifier = KeyMod::LeftOSCommand; break; - case KeyCode::RightOSCommand: newModifier = KeyMod::RightOSCommand; break; - default: newModifier = KeyMod::None; break; - } - if (type == EventType::Key_Down) - { - switch (key.KeyCode) - { - case KeyCode::NumlockClear: newModifier ^= KeyMod::NumLock; break; - case KeyCode::CapsLock: newModifier ^= KeyMod::CapsLock; break; - case KeyCode::ScrollLock: newModifier ^= KeyMod::ScrollLock; break; - default: keyboardState.KeyModState |= newModifier; - } - } - else - { - // Remove from any keymod not pressed from the modifier - keyboardState.KeyModState &= ~newModifier; - } - } - - SystemEvent evt; - evt.Timestamp = timestamp; - evt.Type = type; - evt.Data.Keyboard.AssociatedKeyboardID = kGlobalKeyboardID; - evt.Data.Keyboard.Key = key; - evt.Data.Keyboard.KeyState = { keyPosition, 0.0f }; - evt.Data.Keyboard.KeyModeState = keyboardState.KeyModState; - - bool evtPosted = AddEvent(evt); - - return evtPosted; - } - } // namespace - - bool SendKeyboardKey(uint64 timestamp, KeyboardID ID, Key key, KeyPosition keyPosition) - { - return SendKeyboardKey_Internal(timestamp, ID, key, keyPosition); - } - - void UpdateKeyboardstate(float deltaTime) - { - for (KeyState& state : KeyboardState.KeyState) - { - if (state.Position == KeyPosition::Down) - { - if (state.Time < 0.0f) - { - state.Time = 0.0f; - } - else - { - state.Time += deltaTime; + case KeyCode::NumlockClear: newModifier ^= KeyMod::NumLock; break; + case KeyCode::CapsLock: newModifier ^= KeyMod::CapsLock; break; + case KeyCode::ScrollLock: newModifier ^= KeyMod::ScrollLock; break; + default: keyboardState.KeyModState |= newModifier; } } else { - state.Time = -1.0f; + // Remove from any keymod not pressed from the modifier + keyboardState.KeyModState &= ~newModifier; } } - } - bool IsKeyDown(ScanCode scanCode) + SystemEvent evt; + evt.Timestamp = timestamp; + evt.Type = type; + evt.Data.Keyboard.AssociatedKeyboardID = kGlobalKeyboardID; + evt.Data.Keyboard.Key = key; + evt.Data.Keyboard.KeyState = { keyPosition, 0.0f }; + evt.Data.Keyboard.KeyModeState = keyboardState.KeyModState; + + bool evtPosted = AddEvent(evt); + + return evtPosted; + } +} // namespace + +bool SendKeyboardKey(uint64 timestamp, KeyboardID ID, Key key, KeyPosition keyPosition) +{ + return SendKeyboardKey_Internal(timestamp, ID, key, keyPosition); +} + +void UpdateKeyboardstate(float deltaTime) +{ + for (KeyState& state : KeyboardState.KeyState) { - return KeyboardState.KeyState[ToUnderlying(scanCode)].Position == KeyPosition::Down; + if (state.Position == KeyPosition::Down) + { + if (state.Time < 0.0f) + { + state.Time = 0.0f; + } + else + { + state.Time += deltaTime; + } + } + else + { + state.Time = -1.0f; + } } +} - bool IsKeyPressed(ScanCode scanCode) - { - auto& keyState = KeyboardState.KeyState[ToUnderlying(scanCode)]; - return keyState.Position == KeyPosition::Down && keyState.Time == 0.0f; - } +bool IsKeyDown(ScanCode scanCode) +{ + return KeyboardState.KeyState[ToUnderlying(scanCode)].Position == KeyPosition::Down; +} - KeyMod GetKeyModState() - { - auto& keyboardState = KeyboardState; - return keyboardState.KeyModState; - } +bool IsKeyPressed(ScanCode scanCode) +{ + auto& keyState = KeyboardState.KeyState[ToUnderlying(scanCode)]; + return keyState.Position == KeyPosition::Down && keyState.Time == 0.0f; +} - KeyCode GetKeyCodeFromScanCode(ScanCode scanCode, KeyMod keyModState) - { - return GetKeyCodeFromDefaultMapping(scanCode, keyModState); - } +KeyMod GetKeyModState() +{ + auto& keyboardState = KeyboardState; + return keyboardState.KeyModState; +} - static_assert(sizeof(KeyPosition) == sizeof(bool)); - static_assert(ToUnderlying(KeyPosition::Down) == true); - static_assert(ToUnderlying(KeyPosition::Up) == false); - static_assert(sizeof(ScanCode) == sizeof(uint16)); - static_assert(ToUnderlying(ScanCode::Count) == 512); -} // namespace Juliet +KeyCode GetKeyCodeFromScanCode(ScanCode scanCode, KeyMod keyModState) +{ + return GetKeyCodeFromDefaultMapping(scanCode, keyModState); +} + +static_assert(sizeof(KeyPosition) == sizeof(bool)); +static_assert(ToUnderlying(KeyPosition::Down) == true); +static_assert(ToUnderlying(KeyPosition::Up) == false); +static_assert(sizeof(ScanCode) == sizeof(uint16)); +static_assert(ToUnderlying(ScanCode::Count) == 512); diff --git a/Juliet/src/Core/HAL/Event/KeyboardMapping.cpp b/Juliet/src/Core/HAL/Event/KeyboardMapping.cpp index f6d23f0..d63e2fa 100644 --- a/Juliet/src/Core/HAL/Event/KeyboardMapping.cpp +++ b/Juliet/src/Core/HAL/Event/KeyboardMapping.cpp @@ -1,204 +1,201 @@ -#include +#include #include #include #include #include -namespace Juliet +namespace { - namespace + // clang-format off + KeyCode UnshiftedDefaultSymbols[] = { + KeyCode::Num1, + KeyCode::Num2, + KeyCode::Num3, + KeyCode::Num4, + KeyCode::Num5, + KeyCode::Num6, + KeyCode::Num7, + KeyCode::Num8, + KeyCode::Num9, + KeyCode::Num0, + KeyCode::Return, + KeyCode::Escape, + KeyCode::Backspace, + KeyCode::Tab, + KeyCode::Space, + KeyCode::Minus, + KeyCode::Equals, + KeyCode::LeftBracket, + KeyCode::RightBracket, + KeyCode::Backslash, + KeyCode::Hash, + KeyCode::Semicolon, + KeyCode::Apostrophe, + KeyCode::GraveAccent, + KeyCode::Comma, + KeyCode::Period, + KeyCode::Slash, + }; + + KeyCode ShiftedDefaultSymbols[] = { + KeyCode::ExclamationPoint, + KeyCode::CommercialAt, + KeyCode::Hash, + KeyCode::Dollar, + KeyCode::Percent, + KeyCode::Caret, + KeyCode::Ampersand, + KeyCode::Asterisk, + KeyCode::LeftParenthesis, + KeyCode::RightParenthesis, + KeyCode::Return, + KeyCode::Escape, + KeyCode::Backspace, + KeyCode::Tab, + KeyCode::Space, + KeyCode::Underscore, + KeyCode::Plus, + KeyCode::LeftBrace, + KeyCode::RightBrace, + KeyCode::Pipe, + KeyCode::Hash, + KeyCode::Colon, + KeyCode::DoubleApostrophe, + KeyCode::Tilde, + KeyCode::LessThan, + KeyCode::GreaterThan, + KeyCode::QuestionMark, + }; + // clang-format on + + KeyCode GetNonPrintableKeys(ScanCode scanCode) { - // clang-format off - KeyCode UnshiftedDefaultSymbols[] = { - KeyCode::Num1, - KeyCode::Num2, - KeyCode::Num3, - KeyCode::Num4, - KeyCode::Num5, - KeyCode::Num6, - KeyCode::Num7, - KeyCode::Num8, - KeyCode::Num9, - KeyCode::Num0, - KeyCode::Return, - KeyCode::Escape, - KeyCode::Backspace, - KeyCode::Tab, - KeyCode::Space, - KeyCode::Minus, - KeyCode::Equals, - KeyCode::LeftBracket, - KeyCode::RightBracket, - KeyCode::Backslash, - KeyCode::Hash, - KeyCode::Semicolon, - KeyCode::Apostrophe, - KeyCode::GraveAccent, - KeyCode::Comma, - KeyCode::Period, - KeyCode::Slash, - }; - - KeyCode ShiftedDefaultSymbols[] = { - KeyCode::ExclamationPoint, - KeyCode::CommercialAt, - KeyCode::Hash, - KeyCode::Dollar, - KeyCode::Percent, - KeyCode::Caret, - KeyCode::Ampersand, - KeyCode::Asterisk, - KeyCode::LeftParenthesis, - KeyCode::RightParenthesis, - KeyCode::Return, - KeyCode::Escape, - KeyCode::Backspace, - KeyCode::Tab, - KeyCode::Space, - KeyCode::Underscore, - KeyCode::Plus, - KeyCode::LeftBrace, - KeyCode::RightBrace, - KeyCode::Pipe, - KeyCode::Hash, - KeyCode::Colon, - KeyCode::DoubleApostrophe, - KeyCode::Tilde, - KeyCode::LessThan, - KeyCode::GreaterThan, - KeyCode::QuestionMark, - }; - // clang-format on - - KeyCode GetNonPrintableKeys(ScanCode scanCode) + switch (scanCode) { - switch (scanCode) - { - case ScanCode::Delete: return KeyCode::Delete; - case ScanCode::CapsLock: return KeyCode::CapsLock; - case ScanCode::F1: return KeyCode::F1; - case ScanCode::F2: return KeyCode::F2; - case ScanCode::F3: return KeyCode::F3; - case ScanCode::F4: return KeyCode::F4; - case ScanCode::F5: return KeyCode::F5; - case ScanCode::F6: return KeyCode::F6; - case ScanCode::F7: return KeyCode::F7; - case ScanCode::F8: return KeyCode::F8; - case ScanCode::F9: return KeyCode::F9; - case ScanCode::F10: return KeyCode::F10; - case ScanCode::F11: return KeyCode::F11; - case ScanCode::F12: return KeyCode::F12; - case ScanCode::PrintScreen: return KeyCode::PrintScreen; - case ScanCode::ScrollLock: return KeyCode::ScrollLock; - case ScanCode::Pause: return KeyCode::Pause; - case ScanCode::Insert: return KeyCode::Insert; - case ScanCode::Home: return KeyCode::Home; - case ScanCode::PageUp: return KeyCode::PageUp; - case ScanCode::End: return KeyCode::End; - case ScanCode::PageDown: return KeyCode::PageDown; - case ScanCode::RightArrow: return KeyCode::RightArrow; - case ScanCode::LeftArrow: return KeyCode::LeftArrow; - case ScanCode::DownArrow: return KeyCode::DownArrow; - case ScanCode::UpArrow: return KeyCode::UpArrow; - case ScanCode::NumlockClear: return KeyCode::NumlockClear; - case ScanCode::KeyPad_Divide: return KeyCode::KeyPad_Divide; - case ScanCode::KeyPad_Multiply: return KeyCode::KeyPad_Multiply; - case ScanCode::KeyPad_Minus: return KeyCode::KeyPad_Minus; - case ScanCode::KeyPad_Plus: return KeyCode::KeyPad_Plus; - case ScanCode::KeyPad_Enter: return KeyCode::KeyPad_Enter; - case ScanCode::KeyPad_Num1: return KeyCode::KeyPad_Num1; - case ScanCode::KeyPad_Num2: return KeyCode::KeyPad_Num2; - case ScanCode::KeyPad_Num3: return KeyCode::KeyPad_Num3; - case ScanCode::KeyPad_Num4: return KeyCode::KeyPad_Num4; - case ScanCode::KeyPad_Num5: return KeyCode::KeyPad_Num5; - case ScanCode::KeyPad_Num6: return KeyCode::KeyPad_Num6; - case ScanCode::KeyPad_Num7: return KeyCode::KeyPad_Num7; - case ScanCode::KeyPad_Num8: return KeyCode::KeyPad_Num8; - case ScanCode::KeyPad_Num9: return KeyCode::KeyPad_Num9; - case ScanCode::KeyPad_Num0: return KeyCode::KeyPad_Num0; - case ScanCode::KeyPad_Period: return KeyCode::KeyPad_Period; - case ScanCode::Power: return KeyCode::Power; - case ScanCode::KeyPad_Equals: return KeyCode::KeyPad_Equals; - case ScanCode::F13: return KeyCode::F13; - case ScanCode::F14: return KeyCode::F14; - case ScanCode::F15: return KeyCode::F15; - case ScanCode::F16: return KeyCode::F16; - case ScanCode::F17: return KeyCode::F17; - case ScanCode::F18: return KeyCode::F18; - case ScanCode::F19: return KeyCode::F19; - case ScanCode::F20: return KeyCode::F20; - case ScanCode::F21: return KeyCode::F21; - case ScanCode::F22: return KeyCode::F22; - case ScanCode::F23: return KeyCode::F23; - case ScanCode::F24: return KeyCode::F24; - case ScanCode::Mute: return KeyCode::Mute; - case ScanCode::VolumeUp: return KeyCode::VolumeUp; - case ScanCode::VolumeDown: return KeyCode::VolumeDown; - case ScanCode::KeyPad_Comma: return KeyCode::KeyPad_Comma; - case ScanCode::LeftControl: return KeyCode::LeftControl; - case ScanCode::LeftShift: return KeyCode::LeftShift; - case ScanCode::LeftAlt: return KeyCode::LeftAlt; - case ScanCode::LeftOSCommand: return KeyCode::LeftOSCommand; - case ScanCode::RightControl: return KeyCode::RightControl; - case ScanCode::RightShift: return KeyCode::RightShift; - case ScanCode::RightAlt: return KeyCode::RightAlt; - case ScanCode::RightOSCommand: return KeyCode::RightOSCommand; - case ScanCode::Sleep: return KeyCode::Sleep; - case ScanCode::WakeUp: return KeyCode::WakeUp; - case ScanCode::Media_NextTrack: return KeyCode::Media_NextTrack; - case ScanCode::Media_PreviousTrack: return KeyCode::Media_PreviousTrack; - case ScanCode::Media_Stop: return KeyCode::Media_Stop; - case ScanCode::Media_Eject: return KeyCode::Media_Eject; - case ScanCode::Media_PlayPause: return KeyCode::Media_PlayPause; - case ScanCode::Media_Select: return KeyCode::Media_Select; - default: return KeyCode::Unknown; - } + case ScanCode::Delete: return KeyCode::Delete; + case ScanCode::CapsLock: return KeyCode::CapsLock; + case ScanCode::F1: return KeyCode::F1; + case ScanCode::F2: return KeyCode::F2; + case ScanCode::F3: return KeyCode::F3; + case ScanCode::F4: return KeyCode::F4; + case ScanCode::F5: return KeyCode::F5; + case ScanCode::F6: return KeyCode::F6; + case ScanCode::F7: return KeyCode::F7; + case ScanCode::F8: return KeyCode::F8; + case ScanCode::F9: return KeyCode::F9; + case ScanCode::F10: return KeyCode::F10; + case ScanCode::F11: return KeyCode::F11; + case ScanCode::F12: return KeyCode::F12; + case ScanCode::PrintScreen: return KeyCode::PrintScreen; + case ScanCode::ScrollLock: return KeyCode::ScrollLock; + case ScanCode::Pause: return KeyCode::Pause; + case ScanCode::Insert: return KeyCode::Insert; + case ScanCode::Home: return KeyCode::Home; + case ScanCode::PageUp: return KeyCode::PageUp; + case ScanCode::End: return KeyCode::End; + case ScanCode::PageDown: return KeyCode::PageDown; + case ScanCode::RightArrow: return KeyCode::RightArrow; + case ScanCode::LeftArrow: return KeyCode::LeftArrow; + case ScanCode::DownArrow: return KeyCode::DownArrow; + case ScanCode::UpArrow: return KeyCode::UpArrow; + case ScanCode::NumlockClear: return KeyCode::NumlockClear; + case ScanCode::KeyPad_Divide: return KeyCode::KeyPad_Divide; + case ScanCode::KeyPad_Multiply: return KeyCode::KeyPad_Multiply; + case ScanCode::KeyPad_Minus: return KeyCode::KeyPad_Minus; + case ScanCode::KeyPad_Plus: return KeyCode::KeyPad_Plus; + case ScanCode::KeyPad_Enter: return KeyCode::KeyPad_Enter; + case ScanCode::KeyPad_Num1: return KeyCode::KeyPad_Num1; + case ScanCode::KeyPad_Num2: return KeyCode::KeyPad_Num2; + case ScanCode::KeyPad_Num3: return KeyCode::KeyPad_Num3; + case ScanCode::KeyPad_Num4: return KeyCode::KeyPad_Num4; + case ScanCode::KeyPad_Num5: return KeyCode::KeyPad_Num5; + case ScanCode::KeyPad_Num6: return KeyCode::KeyPad_Num6; + case ScanCode::KeyPad_Num7: return KeyCode::KeyPad_Num7; + case ScanCode::KeyPad_Num8: return KeyCode::KeyPad_Num8; + case ScanCode::KeyPad_Num9: return KeyCode::KeyPad_Num9; + case ScanCode::KeyPad_Num0: return KeyCode::KeyPad_Num0; + case ScanCode::KeyPad_Period: return KeyCode::KeyPad_Period; + case ScanCode::Power: return KeyCode::Power; + case ScanCode::KeyPad_Equals: return KeyCode::KeyPad_Equals; + case ScanCode::F13: return KeyCode::F13; + case ScanCode::F14: return KeyCode::F14; + case ScanCode::F15: return KeyCode::F15; + case ScanCode::F16: return KeyCode::F16; + case ScanCode::F17: return KeyCode::F17; + case ScanCode::F18: return KeyCode::F18; + case ScanCode::F19: return KeyCode::F19; + case ScanCode::F20: return KeyCode::F20; + case ScanCode::F21: return KeyCode::F21; + case ScanCode::F22: return KeyCode::F22; + case ScanCode::F23: return KeyCode::F23; + case ScanCode::F24: return KeyCode::F24; + case ScanCode::Mute: return KeyCode::Mute; + case ScanCode::VolumeUp: return KeyCode::VolumeUp; + case ScanCode::VolumeDown: return KeyCode::VolumeDown; + case ScanCode::KeyPad_Comma: return KeyCode::KeyPad_Comma; + case ScanCode::LeftControl: return KeyCode::LeftControl; + case ScanCode::LeftShift: return KeyCode::LeftShift; + case ScanCode::LeftAlt: return KeyCode::LeftAlt; + case ScanCode::LeftOSCommand: return KeyCode::LeftOSCommand; + case ScanCode::RightControl: return KeyCode::RightControl; + case ScanCode::RightShift: return KeyCode::RightShift; + case ScanCode::RightAlt: return KeyCode::RightAlt; + case ScanCode::RightOSCommand: return KeyCode::RightOSCommand; + case ScanCode::Sleep: return KeyCode::Sleep; + case ScanCode::WakeUp: return KeyCode::WakeUp; + case ScanCode::Media_NextTrack: return KeyCode::Media_NextTrack; + case ScanCode::Media_PreviousTrack: return KeyCode::Media_PreviousTrack; + case ScanCode::Media_Stop: return KeyCode::Media_Stop; + case ScanCode::Media_Eject: return KeyCode::Media_Eject; + case ScanCode::Media_PlayPause: return KeyCode::Media_PlayPause; + case ScanCode::Media_Select: return KeyCode::Media_Select; + default: return KeyCode::Unknown; } - } // namespace - - KeyCode GetKeyCodeFromDefaultMapping(ScanCode scanCode, KeyMod keyModState) - { - if (scanCode <= ScanCode::Unknown || scanCode > ScanCode::Count) - { - Assert(false , "Unsupported KeyCode (out of bounds)"); - return KeyCode::Unknown; - } - - if (scanCode < ScanCode::A) - { - return KeyCode::Unknown; - } - - // Handles A-Z characters - if (scanCode <= ScanCode::Z) - { - const auto index = scanCode - ScanCode::A; - bool isShiftPressed = (keyModState & KeyMod::Shift) != KeyMod::None; - if ((keyModState & KeyMod::CapsLock) != KeyMod::None) - { - isShiftPressed = !isShiftPressed; - } - - if (isShiftPressed) - { - return ToEnum(static_cast('A') + index); - } - return ToEnum(static_cast('a') + index); - } - - // Handles Num1 to Num0 - if (scanCode <= ScanCode::Num0) - { - const auto index = scanCode - ScanCode::Num1; - const bool isShiftPressed = (keyModState & KeyMod::Shift) != KeyMod::None; - if (isShiftPressed) - { - return ShiftedDefaultSymbols[index]; - } - return UnshiftedDefaultSymbols[index]; - } - - // Handle everything else (characters that do not convert to ASCII code) - return GetNonPrintableKeys(scanCode); } -} // namespace Juliet +} // namespace + +KeyCode GetKeyCodeFromDefaultMapping(ScanCode scanCode, KeyMod keyModState) +{ + if (scanCode <= ScanCode::Unknown || scanCode > ScanCode::Count) + { + Assert(false , "Unsupported KeyCode (out of bounds)"); + return KeyCode::Unknown; + } + + if (scanCode < ScanCode::A) + { + return KeyCode::Unknown; + } + + // Handles A-Z characters + if (scanCode <= ScanCode::Z) + { + const auto index = scanCode - ScanCode::A; + bool isShiftPressed = (keyModState & KeyMod::Shift) != KeyMod::None; + if ((keyModState & KeyMod::CapsLock) != KeyMod::None) + { + isShiftPressed = !isShiftPressed; + } + + if (isShiftPressed) + { + return ToEnum(static_cast('A') + index); + } + return ToEnum(static_cast('a') + index); + } + + // Handles Num1 to Num0 + if (scanCode <= ScanCode::Num0) + { + const auto index = scanCode - ScanCode::Num1; + const bool isShiftPressed = (keyModState & KeyMod::Shift) != KeyMod::None; + if (isShiftPressed) + { + return ShiftedDefaultSymbols[index]; + } + return UnshiftedDefaultSymbols[index]; + } + + // Handle everything else (characters that do not convert to ASCII code) + return GetNonPrintableKeys(scanCode); +} diff --git a/Juliet/src/Core/HAL/Event/KeyboardMapping.h b/Juliet/src/Core/HAL/Event/KeyboardMapping.h index c1ece03..494d64a 100644 --- a/Juliet/src/Core/HAL/Event/KeyboardMapping.h +++ b/Juliet/src/Core/HAL/Event/KeyboardMapping.h @@ -1,10 +1,7 @@ -#pragma once +#pragma once #include #include -namespace Juliet -{ - // Transforms ScanCode into KeyCode using the default US ASCII Mapping - extern KeyCode GetKeyCodeFromDefaultMapping(ScanCode scanCode, KeyMod keyModState); -} // namespace Juliet +// Transforms ScanCode into KeyCode using the default US ASCII Mapping +extern KeyCode GetKeyCodeFromDefaultMapping(ScanCode scanCode, KeyMod keyModState); diff --git a/Juliet/src/Core/HAL/Event/Keyboard_Private.h b/Juliet/src/Core/HAL/Event/Keyboard_Private.h index 00f8e7d..42a7094 100644 --- a/Juliet/src/Core/HAL/Event/Keyboard_Private.h +++ b/Juliet/src/Core/HAL/Event/Keyboard_Private.h @@ -1,12 +1,9 @@ -#pragma once +#pragma once #include #include -namespace Juliet -{ - extern bool SendKeyboardKey(uint64 timestamp, KeyboardID ID, Key key, KeyPosition keyPosition); - extern void UpdateKeyboardstate(float deltaTime); +extern bool SendKeyboardKey(uint64 timestamp, KeyboardID ID, Key key, KeyPosition keyPosition); +extern void UpdateKeyboardstate(float deltaTime); - extern const KeyboardID kGlobalKeyboardID; -} // namespace Juliet +extern const KeyboardID kGlobalKeyboardID; diff --git a/Juliet/src/Core/HAL/Event/Mouse.cpp b/Juliet/src/Core/HAL/Event/Mouse.cpp index f34d905..28ca680 100644 --- a/Juliet/src/Core/HAL/Event/Mouse.cpp +++ b/Juliet/src/Core/HAL/Event/Mouse.cpp @@ -1,158 +1,155 @@ -#include +#include #include #include #include #include -namespace Juliet +namespace { - namespace + Mouse MouseState; + + void ConstraintMousePositionToWindow(Mouse& mouseState, Window* window, float& x, float& y) { - Mouse MouseState; + float x_min = 0.f, x_max = (float)(window->Width - 1); + float y_min = 0.f, y_max = (float)(window->Height - 1); - void ConstraintMousePositionToWindow(Mouse& mouseState, Window* window, float& x, float& y) + if (x >= (x_max + 1)) { - float x_min = 0.f, x_max = (float)(window->Width - 1); - float y_min = 0.f, y_max = (float)(window->Height - 1); - - if (x >= (x_max + 1)) - { - x = std::max(x_max, mouseState.X_Previous); - } - x = std::max(x, x_min); - - if (y >= (y_max + 1)) - { - y = std::max(y_max, mouseState.Y_Previous); - } - y = std::max(y, y_min); + x = std::max(x_max, mouseState.X_Previous); } + x = std::max(x, x_min); - void SendMouseMotion_Internal(uint64 timestamp, Window* window, MouseID mouseID, float x, float y) + if (y >= (y_max + 1)) { - auto& mouseState = GetMouseState(); - float xDisplacement = 0.0f; - float yDisplacement = 0.0f; - - ConstraintMousePositionToWindow(mouseState, window, x, y); - - if (mouseState.HasPosition) - { - xDisplacement = x - mouseState.X_Previous; - yDisplacement = y - mouseState.Y_Previous; - } - - if (mouseState.HasPosition && xDisplacement == 0.0f && yDisplacement == 0.0f) - { - // Skip it because state didnt change - return; - } - - mouseState.X = x; - mouseState.Y = y; - mouseState.HasPosition = true; - - mouseState.X_Previous = x; - mouseState.Y_Previous = y; - - mouseState.DeltaX += xDisplacement; - mouseState.DeltaY += yDisplacement; - - SystemEvent evt; - evt.Type = EventType::Mouse_Move; - evt.Timestamp = timestamp; - evt.Data.MouseMovement.WindowID = window->ID; - evt.Data.MouseMovement.AssociatedMouseID = mouseID; - evt.Data.MouseMovement.X = x; - evt.Data.MouseMovement.Y = y; - evt.Data.MouseMovement.X_Displacement = xDisplacement; - evt.Data.MouseMovement.Y_Displacement = yDisplacement; - evt.Data.MouseMovement.ButtonState = mouseState.ButtonState; - AddEvent(evt); + y = std::max(y_max, mouseState.Y_Previous); } - - } // namespace - - constexpr MouseID kGlobalMouseID = 0; - - Mouse& GetMouseState() - { - return MouseState; + y = std::max(y, y_min); } - void SendMouseMotion(uint64 timestamp, NonNullPtr window, MouseID ID, float x, float y) + void SendMouseMotion_Internal(uint64 timestamp, Window* window, MouseID mouseID, float x, float y) { - // TODO : Update Mouse focus and send Mouse Enter / Mouse Leave event + auto& mouseState = GetMouseState(); + float xDisplacement = 0.0f; + float yDisplacement = 0.0f; - SendMouseMotion_Internal(timestamp, window, ID, x, y); - } + ConstraintMousePositionToWindow(mouseState, window, x, y); - void SendMouseButton(uint64 timestamp, NonNullPtr window, MouseID mouseID, MouseButton button, bool pressed) - { - Mouse& mouseState = GetMouseState(); - MouseButton flags = mouseState.ButtonState; - - auto type = EventType::None; - if (pressed) + if (mouseState.HasPosition) { - type = EventType::Mouse_ButtonPressed; - flags |= button; - } - else - { - type = EventType::Mouse_ButtonReleased; - flags = flags & ~button; + xDisplacement = x - mouseState.X_Previous; + yDisplacement = y - mouseState.Y_Previous; } - if (flags == mouseState.ButtonState) + if (mouseState.HasPosition && xDisplacement == 0.0f && yDisplacement == 0.0f) { + // Skip it because state didnt change return; } - mouseState.ButtonState = flags; + mouseState.X = x; + mouseState.Y = y; + mouseState.HasPosition = true; + + mouseState.X_Previous = x; + mouseState.Y_Previous = y; + + mouseState.DeltaX += xDisplacement; + mouseState.DeltaY += yDisplacement; - // TODO : Send Event! SystemEvent evt; - evt.Timestamp = timestamp; - evt.Type = type; - evt.Data.MouseButton.AssociatedMouseID = mouseID; - evt.Data.MouseButton.WindowID = window->ID; - evt.Data.MouseButton.ButtonState = button; - evt.Data.MouseButton.X = mouseState.X; - evt.Data.MouseButton.Y = mouseState.Y; - evt.Data.MouseButton.IsPressed = pressed; + evt.Type = EventType::Mouse_Move; + evt.Timestamp = timestamp; + evt.Data.MouseMovement.WindowID = window->ID; + evt.Data.MouseMovement.AssociatedMouseID = mouseID; + evt.Data.MouseMovement.X = x; + evt.Data.MouseMovement.Y = y; + evt.Data.MouseMovement.X_Displacement = xDisplacement; + evt.Data.MouseMovement.Y_Displacement = yDisplacement; + evt.Data.MouseMovement.ButtonState = mouseState.ButtonState; AddEvent(evt); } - bool IsMouseButtonDown(MouseButton button) +} // namespace + +constexpr MouseID kGlobalMouseID = 0; + +Mouse& GetMouseState() +{ + return MouseState; +} + +void SendMouseMotion(uint64 timestamp, NonNullPtr window, MouseID ID, float x, float y) +{ + // TODO : Update Mouse focus and send Mouse Enter / Mouse Leave event + + SendMouseMotion_Internal(timestamp, window, ID, x, y); +} + +void SendMouseButton(uint64 timestamp, NonNullPtr window, MouseID mouseID, MouseButton button, bool pressed) +{ + Mouse& mouseState = GetMouseState(); + MouseButton flags = mouseState.ButtonState; + + auto type = EventType::None; + if (pressed) { - auto& mouseState = GetMouseState(); - return (mouseState.ButtonState & button) != MouseButton::None; + type = EventType::Mouse_ButtonPressed; + flags |= button; + } + else + { + type = EventType::Mouse_ButtonReleased; + flags = flags & ~button; } - MousePosition GetMousePosition() + if (flags == mouseState.ButtonState) { - auto& mouseState = GetMouseState(); - return { .X = mouseState.X, .Y = mouseState.Y }; + return; } - MousePosition GetMouseDelta() - { - auto& mouseState = GetMouseState(); - return { .X = mouseState.DeltaX, .Y = mouseState.DeltaY }; - } + mouseState.ButtonState = flags; - MouseButton GetMouseButtonState() - { - const auto& mouseState = GetMouseState(); - return mouseState.ButtonState; - } + // TODO : Send Event! + SystemEvent evt; + evt.Timestamp = timestamp; + evt.Type = type; + evt.Data.MouseButton.AssociatedMouseID = mouseID; + evt.Data.MouseButton.WindowID = window->ID; + evt.Data.MouseButton.ButtonState = button; + evt.Data.MouseButton.X = mouseState.X; + evt.Data.MouseButton.Y = mouseState.Y; + evt.Data.MouseButton.IsPressed = pressed; + AddEvent(evt); +} - void UpdateMouseState() - { - auto& mouseState = GetMouseState(); - mouseState.DeltaX = 0.0f; - mouseState.DeltaY = 0.0f; - } +bool IsMouseButtonDown(MouseButton button) +{ + auto& mouseState = GetMouseState(); + return (mouseState.ButtonState & button) != MouseButton::None; +} + +MousePosition GetMousePosition() +{ + auto& mouseState = GetMouseState(); + return { .X = mouseState.X, .Y = mouseState.Y }; +} + +MousePosition GetMouseDelta() +{ + auto& mouseState = GetMouseState(); + return { .X = mouseState.DeltaX, .Y = mouseState.DeltaY }; +} + +MouseButton GetMouseButtonState() +{ + const auto& mouseState = GetMouseState(); + return mouseState.ButtonState; +} + +void UpdateMouseState() +{ + auto& mouseState = GetMouseState(); + mouseState.DeltaX = 0.0f; + mouseState.DeltaY = 0.0f; +} -} // namespace Juliet diff --git a/Juliet/src/Core/HAL/Event/Mouse_Private.h b/Juliet/src/Core/HAL/Event/Mouse_Private.h index c5ab485..ddb76bd 100644 --- a/Juliet/src/Core/HAL/Event/Mouse_Private.h +++ b/Juliet/src/Core/HAL/Event/Mouse_Private.h @@ -1,32 +1,29 @@ -#pragma once +#pragma once #include -namespace Juliet +struct Window; + +struct Mouse { - struct Window; + float X; + float Y; - struct Mouse - { - float X; - float Y; + float X_Previous; + float Y_Previous; - float X_Previous; - float Y_Previous; + float DeltaX; + float DeltaY; - float DeltaX; - float DeltaY; + MouseButton ButtonState; - MouseButton ButtonState; + bool HasPosition : 1; +}; - bool HasPosition : 1; - }; +Mouse& GetMouseState(); - Mouse& GetMouseState(); +extern void UpdateMouseState(); +extern void SendMouseMotion(uint64 timestamp, NonNullPtr window, MouseID ID, float x, float y); +extern void SendMouseButton(uint64 timestamp, NonNullPtr window, MouseID mouseID, MouseButton button, bool pressed); - extern void UpdateMouseState(); - extern void SendMouseMotion(uint64 timestamp, NonNullPtr window, MouseID ID, float x, float y); - extern void SendMouseButton(uint64 timestamp, NonNullPtr window, MouseID mouseID, MouseButton button, bool pressed); - - extern const MouseID kGlobalMouseID; -} // namespace Juliet +extern const MouseID kGlobalMouseID; diff --git a/Juliet/src/Core/HAL/Event/SystemEvent.cpp b/Juliet/src/Core/HAL/Event/SystemEvent.cpp index 1096979..e37d5a3 100644 --- a/Juliet/src/Core/HAL/Event/SystemEvent.cpp +++ b/Juliet/src/Core/HAL/Event/SystemEvent.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -9,92 +9,89 @@ #pragma pop_macro("global") -namespace Juliet +namespace { - namespace + // TODO : make my own queue / using vector + std::queue eventQueue; + + // Update all systems event loops and gather events into the main queue + void PumpEvents() { - // TODO : make my own queue / using vector - std::queue eventQueue; - - // Update all systems event loops and gather events into the main queue - void PumpEvents() + if (DisplayDevice* displayDevice = GetDisplayDevice()) { - if (DisplayDevice* displayDevice = GetDisplayDevice()) - { - displayDevice->PumpEvents(displayDevice); - } + displayDevice->PumpEvents(displayDevice); } - - bool AddEvent_Internal(const SystemEvent& event) - { - auto& newEvent = eventQueue.emplace(); - newEvent = event; - - // TODO : Logs - - return true; - } - } // namespace - - bool GetEvent(SystemEvent& event) - { - return WaitEvent(event, 0); } - bool WaitEvent(SystemEvent& event, int32 timeoutInNS /* = -1 */) + bool AddEvent_Internal(const SystemEvent& event) { - using namespace std::chrono; + auto& newEvent = eventQueue.emplace(); + newEvent = event; - // Handle the "Infinite Wait" and "Timed Wait" logic - const bool isInfinite = (timeoutInNS < 0); - const nanoseconds timeout(timeoutInNS); - const auto startTime = steady_clock::now(); + // TODO : Logs - while (true) + return true; + } +} // namespace + +bool GetEvent(SystemEvent& event) +{ + return WaitEvent(event, 0); +} + +bool WaitEvent(SystemEvent& event, int32 timeoutInNS /* = -1 */) +{ + using namespace std::chrono; + + // Handle the "Infinite Wait" and "Timed Wait" logic + const bool isInfinite = (timeoutInNS < 0); + const nanoseconds timeout(timeoutInNS); + const auto startTime = steady_clock::now(); + + while (true) + { + PumpEvents(); + + if (!eventQueue.empty()) { - PumpEvents(); + event = eventQueue.front(); + eventQueue.pop(); + return true; + } - if (!eventQueue.empty()) - { - event = eventQueue.front(); - eventQueue.pop(); - return true; - } + // If timeout is 0, we only check once (PumpEvents already ran) + if (timeoutInNS == 0) + { + break; + } - // If timeout is 0, we only check once (PumpEvents already ran) - if (timeoutInNS == 0) + // Check if we have exceeded our time limit + if (!isInfinite) + { + auto elapsed = steady_clock::now() - startTime; + if (elapsed >= timeout) { break; } - - // Check if we have exceeded our time limit - if (!isInfinite) - { - auto elapsed = steady_clock::now() - startTime; - if (elapsed >= timeout) - { - break; - } - } } - - return false; } - bool AddEvent(SystemEvent& event) + return false; +} + +bool AddEvent(SystemEvent& event) +{ + if (event.Timestamp == 0) { - if (event.Timestamp == 0) - { - event.Timestamp = 1; // TODO : Clock::Now(); - } - - return AddEvent_Internal(event); + event.Timestamp = 1; // TODO : Clock::Now(); } - void Events_NewFrame(float deltaTime) - { - UpdateKeyboardstate(deltaTime); - UpdateMouseState(); - } + return AddEvent_Internal(event); +} + +void Events_NewFrame(float deltaTime) +{ + UpdateKeyboardstate(deltaTime); + UpdateMouseState(); +} -} // namespace Juliet diff --git a/Juliet/src/Core/HAL/Event/Win32ScanCode.h b/Juliet/src/Core/HAL/Event/Win32ScanCode.h index 732dcaa..980ceba 100644 --- a/Juliet/src/Core/HAL/Event/Win32ScanCode.h +++ b/Juliet/src/Core/HAL/Event/Win32ScanCode.h @@ -1,8 +1,8 @@ -#pragma once +#pragma once #include -namespace Juliet::Win32 +namespace Win32 { // Conversion table from Win32 scan code to HID Usage Page (see Keyboard.h) // https://learn.microsoft.com/en-us/windows/win32/inputdev/about-keyboard-input#extended-key-flag @@ -267,4 +267,4 @@ namespace Juliet::Win32 }; // clang-format on -} // namespace Juliet::Win32 +} // namespace Win32 diff --git a/Juliet/src/Core/HAL/Event/WindowEvent.cpp b/Juliet/src/Core/HAL/Event/WindowEvent.cpp index 9cfd9be..3852a48 100644 --- a/Juliet/src/Core/HAL/Event/WindowEvent.cpp +++ b/Juliet/src/Core/HAL/Event/WindowEvent.cpp @@ -1,21 +1,18 @@ -#include +#include #include #include -namespace Juliet +bool SendWindowEvent(Window* window, EventType type) { - bool SendWindowEvent(Window* window, EventType type) - { - Assert(window); + Assert(window); - SystemEvent evt; - evt.Timestamp = 0; - evt.Type = type; - evt.Data.Window.AssociatedWindowID = window->ID; + SystemEvent evt; + evt.Timestamp = 0; + evt.Type = type; + evt.Data.Window.AssociatedWindowID = window->ID; - bool evtPosted = AddEvent(evt); + bool evtPosted = AddEvent(evt); - return evtPosted; - } + return evtPosted; +} -} // namespace Juliet diff --git a/Juliet/src/Core/HAL/Event/WindowEvent.h b/Juliet/src/Core/HAL/Event/WindowEvent.h index 2252f51..5f249cf 100644 --- a/Juliet/src/Core/HAL/Event/WindowEvent.h +++ b/Juliet/src/Core/HAL/Event/WindowEvent.h @@ -1,9 +1,6 @@ -#pragma once +#pragma once -namespace Juliet -{ - struct Window; - enum class EventType : uint32; +struct Window; +enum class EventType : uint32; - extern bool SendWindowEvent(Window* window, EventType type); -} // namespace Juliet +extern bool SendWindowEvent(Window* window, EventType type); diff --git a/Juliet/src/Core/HAL/Filesystem/Filesystem.cpp b/Juliet/src/Core/HAL/Filesystem/Filesystem.cpp index 8586b83..82841ef 100644 --- a/Juliet/src/Core/HAL/Filesystem/Filesystem.cpp +++ b/Juliet/src/Core/HAL/Filesystem/Filesystem.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -9,93 +9,90 @@ #include #include -namespace Juliet +namespace { - namespace - { - String CachedBasePath = {}; - String CachedAssetBasePath = {}; + String CachedBasePath = {}; + String CachedAssetBasePath = {}; - bool DirectoryExists(const char* path) + bool DirectoryExists(const char* path) + { + Assert(path); + DWORD attributes = GetFileAttributesA(path); + return (attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY); + } +} // namespace + +String GetBasePath() +{ + Assert(IsValid(CachedBasePath)); + return CachedBasePath; +} + +String GetAssetBasePath() +{ + Assert(IsValid(CachedAssetBasePath)); + return CachedAssetBasePath; +} + +[[nodiscard]] String GetAssetPath(NonNullPtr arena, String filename) +{ + Assert(IsValid(CachedAssetBasePath)); + Assert(IsValid(filename)); + + size_t totalSize = CachedAssetBasePath.Size + filename.Size + 1; + char* buffer = ArenaPushArray(arena, totalSize); + Assert(buffer); + + juliet_snprintf(buffer, totalSize, "%s%s", CStr(CachedAssetBasePath), CStr(filename)); + return { buffer, totalSize - 1 }; +} + +bool IsAbsolutePath(String path) +{ + if (!IsValid(path)) + { + return false; + } + return Platform::IsAbsolutePath(path); +} + +void InitFilesystem(NonNullPtr arena) +{ + CachedBasePath = Platform::GetBasePath(arena); + + String basePath = GetBasePath(); + Assert(IsValid(basePath)); + + // Probe candidate paths for compiled shader directory + // 1. Shipping layout: Assets/Shaders/ next to the exe + // 2. Dev layout: ../../Assets/compiled/ (exe is in bin/x64Clang-/) + constexpr const char* kCandidates[] = { "Assets/Shaders/", "../../Assets/compiled/" }; + + for (const char* candidate : kCandidates) + { + char probePath[512]; + juliet_snprintf(probePath, sizeof(probePath), "%s%s", CStr(basePath), candidate); + + if (DirectoryExists(probePath)) { - Assert(path); - DWORD attributes = GetFileAttributesA(path); - return (attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY); - } - } // namespace - - String GetBasePath() - { - Assert(IsValid(CachedBasePath)); - return CachedBasePath; - } - - String GetAssetBasePath() - { - Assert(IsValid(CachedAssetBasePath)); - return CachedAssetBasePath; - } - - [[nodiscard]] String GetAssetPath(NonNullPtr arena, String filename) - { - Assert(IsValid(CachedAssetBasePath)); - Assert(IsValid(filename)); - - size_t totalSize = CachedAssetBasePath.Size + filename.Size + 1; - char* buffer = ArenaPushArray(arena, totalSize); - Assert(buffer); - - juliet_snprintf(buffer, totalSize, "%s%s", CStr(CachedAssetBasePath), CStr(filename)); - return { buffer, totalSize - 1 }; - } - - bool IsAbsolutePath(String path) - { - if (!IsValid(path)) - { - return false; - } - return Platform::IsAbsolutePath(path); - } - - void InitFilesystem(NonNullPtr arena) - { - CachedBasePath = Platform::GetBasePath(arena); - - String basePath = GetBasePath(); - Assert(IsValid(basePath)); - - // Probe candidate paths for compiled shader directory - // 1. Shipping layout: Assets/Shaders/ next to the exe - // 2. Dev layout: ../../Assets/compiled/ (exe is in bin/x64Clang-/) - constexpr const char* kCandidates[] = { "Assets/Shaders/", "../../Assets/compiled/" }; - - for (const char* candidate : kCandidates) - { - char probePath[512]; - juliet_snprintf(probePath, sizeof(probePath), "%s%s", CStr(basePath), candidate); - - if (DirectoryExists(probePath)) + size_t len = strlen(probePath); + if (char* buffer = ArenaPushArray(arena, len + 1 JULIET_DEBUG_PARAM("CachedAssetBasePath"))) { - size_t len = strlen(probePath); - if (char* buffer = ArenaPushArray(arena, len + 1 JULIET_DEBUG_PARAM("CachedAssetBasePath"))) - { - juliet_snprintf(buffer, len + 1, "%s", probePath); - CachedAssetBasePath = { buffer, len }; - Log(LogLevel::Message, LogCategory::Core, "Asset base path: %s", buffer); - } - return; + juliet_snprintf(buffer, len + 1, "%s", probePath); + CachedAssetBasePath = { buffer, len }; + Log(LogLevel::Message, LogCategory::Core, "Asset base path: %s", buffer); } + return; } - - Log(LogLevel::Error, LogCategory::Core, "Filesystem: Could not find Assets/compiled/ directory!"); } - void ShutdownFilesystem() - { - CachedBasePath.Size = 0; - CachedBasePath.Str = nullptr; - CachedAssetBasePath.Size = 0; - CachedAssetBasePath.Str = nullptr; - } -} // namespace Juliet + Log(LogLevel::Error, LogCategory::Core, "Filesystem: Could not find Assets/compiled/ directory!"); +} + +void ShutdownFilesystem() +{ + CachedBasePath.Size = 0; + CachedBasePath.Str = nullptr; + CachedAssetBasePath.Size = 0; + CachedAssetBasePath.Str = nullptr; +} diff --git a/Juliet/src/Core/HAL/Filesystem/Filesystem_Platform.h b/Juliet/src/Core/HAL/Filesystem/Filesystem_Platform.h index edc72ff..a5ccb47 100644 --- a/Juliet/src/Core/HAL/Filesystem/Filesystem_Platform.h +++ b/Juliet/src/Core/HAL/Filesystem/Filesystem_Platform.h @@ -1,7 +1,7 @@ -#pragma once +#pragma once -namespace Juliet::Platform +namespace Platform { extern String GetBasePath(NonNullPtr arena); extern bool IsAbsolutePath(String path); -} // namespace Juliet::Platform +} // namespace Platform diff --git a/Juliet/src/Core/HAL/Filesystem/Filesystem_Private.h b/Juliet/src/Core/HAL/Filesystem/Filesystem_Private.h index 859cc2a..37c8e81 100644 --- a/Juliet/src/Core/HAL/Filesystem/Filesystem_Private.h +++ b/Juliet/src/Core/HAL/Filesystem/Filesystem_Private.h @@ -1,7 +1,4 @@ -#pragma once +#pragma once -namespace Juliet -{ - extern void InitFilesystem(NonNullPtr arena); - extern void ShutdownFilesystem(); -} // namespace Juliet +extern void InitFilesystem(NonNullPtr arena); +extern void ShutdownFilesystem(); diff --git a/Juliet/src/Core/HAL/Filesystem/Win32/Win32Filesystem.cpp b/Juliet/src/Core/HAL/Filesystem/Win32/Win32Filesystem.cpp index a7c1c9c..8416103 100644 --- a/Juliet/src/Core/HAL/Filesystem/Win32/Win32Filesystem.cpp +++ b/Juliet/src/Core/HAL/Filesystem/Win32/Win32Filesystem.cpp @@ -1,11 +1,11 @@ -#include +#include #include #include #include #include #include -namespace Juliet::Platform +namespace Platform { String GetBasePath(NonNullPtr arena) { @@ -91,4 +91,4 @@ namespace Juliet::Platform return false; } -} // namespace Juliet::Platform +} // namespace Platform diff --git a/Juliet/src/Core/HAL/IO/IOStream.cpp b/Juliet/src/Core/HAL/IO/IOStream.cpp index a59458d..7c5aafe 100644 --- a/Juliet/src/Core/HAL/IO/IOStream.cpp +++ b/Juliet/src/Core/HAL/IO/IOStream.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -6,221 +6,218 @@ #include #include -namespace Juliet +IOStream* IOFromFile(NonNullPtr arena, String filename, String mode) { - IOStream* IOFromFile(NonNullPtr arena, String filename, String mode) + if (!IsValid(filename)) { - if (!IsValid(filename)) - { - Log(LogLevel::Error, LogCategory::Core, "Trying to open IOStream on invalid filename"); - return nullptr; - } - if (!IsValid(mode)) - { - Log(LogLevel::Error, LogCategory::Core, "Trying to open IOStream with invalid mode"); - return nullptr; - } - - return Internal::IOFromFile(arena, filename, mode); + Log(LogLevel::Error, LogCategory::Core, "Trying to open IOStream on invalid filename"); + return nullptr; + } + if (!IsValid(mode)) + { + Log(LogLevel::Error, LogCategory::Core, "Trying to open IOStream with invalid mode"); + return nullptr; } - IOStream* IOFromInterface(NonNullPtr arena, NonNullPtr streamInterface, - NonNullPtr payload) + return Internal::IOFromFile(arena, filename, mode); +} + +IOStream* IOFromInterface(NonNullPtr arena, NonNullPtr streamInterface, + NonNullPtr payload) +{ + Assert(streamInterface->Version >= sizeof(*streamInterface.Get())); + auto stream = ArenaPushStruct(arena); + if (stream) { - Assert(streamInterface->Version >= sizeof(*streamInterface.Get())); - auto stream = ArenaPushStruct(arena); - if (stream) - { - IOStreamInterface* dstInterface = &stream->Interface; - const IOStreamInterface* srcInterface = streamInterface.Get(); - static_assert(sizeof(*(dstInterface)) == sizeof(*(srcInterface)), "Source and Destination type mismatch"); - MemCopy(dstInterface, srcInterface, sizeof(*srcInterface)); - stream->Data = payload.Get(); - } - return stream; + IOStreamInterface* dstInterface = &stream->Interface; + const IOStreamInterface* srcInterface = streamInterface.Get(); + static_assert(sizeof(*(dstInterface)) == sizeof(*(srcInterface)), "Source and Destination type mismatch"); + MemCopy(dstInterface, srcInterface, sizeof(*srcInterface)); + stream->Data = payload.Get(); + } + return stream; +} + +size_t IOPrintf(NonNullPtr stream, _Printf_format_string_ const char* format, ...) +{ + // TODO: Juliet format function should be able to allocate on scratch arena here. + // This buffer should be big enough until then + char formattedBuffer[4096]; + va_list args; + + va_start(args, format); + int writtenSize = vsprintf_s(formattedBuffer, format, args); // Cast to void to ignore the return type. TODO : Juliet format function + va_end(args); + + Assert(writtenSize >= 0); + + ByteBuffer buffer = { .Data = reinterpret_cast(formattedBuffer), .Size = static_cast(writtenSize) }; + return IOWrite(stream, buffer); +} + +size_t IOWrite(NonNullPtr stream, ByteBuffer inBuffer) +{ + if (!stream->Interface.Write) + { + stream->Status = IOStreamStatus::ReadOnly; + Log(LogLevel::Error, LogCategory::Core, "Trying to write to a readonly IOStream"); + return 0; } - size_t IOPrintf(NonNullPtr stream, _Printf_format_string_ const char* format, ...) + stream->Status = IOStreamStatus::Ready; + + if (!IsValid(inBuffer)) { - // TODO: Juliet format function should be able to allocate on scratch arena here. - // This buffer should be big enough until then - char formattedBuffer[4096]; - va_list args; - - va_start(args, format); - int writtenSize = vsprintf_s(formattedBuffer, format, args); // Cast to void to ignore the return type. TODO : Juliet format function - va_end(args); - - Assert(writtenSize >= 0); - - ByteBuffer buffer = { .Data = reinterpret_cast(formattedBuffer), .Size = static_cast(writtenSize) }; - return IOWrite(stream, buffer); + return 0; } - size_t IOWrite(NonNullPtr stream, ByteBuffer inBuffer) + size_t writtenBytes = stream->Interface.Write(stream->Data, inBuffer, &stream->Status); + if ((writtenBytes == 0) && (stream->Status == IOStreamStatus::Ready)) { - if (!stream->Interface.Write) - { - stream->Status = IOStreamStatus::ReadOnly; - Log(LogLevel::Error, LogCategory::Core, "Trying to write to a readonly IOStream"); - return 0; - } + stream->Status = IOStreamStatus::Error; + } + return writtenBytes; +} - stream->Status = IOStreamStatus::Ready; - - if (!IsValid(inBuffer)) - { - return 0; - } - - size_t writtenBytes = stream->Interface.Write(stream->Data, inBuffer, &stream->Status); - if ((writtenBytes == 0) && (stream->Status == IOStreamStatus::Ready)) - { - stream->Status = IOStreamStatus::Error; - } - return writtenBytes; +size_t IORead(NonNullPtr stream, void* ptr, size_t size) +{ + if (!stream->Interface.Read) + { + Log(LogLevel::Error, LogCategory::Core, "Trying to read a writeonly IOStream"); + stream->Status = IOStreamStatus::WriteOnly; + return 0; } - size_t IORead(NonNullPtr stream, void* ptr, size_t size) + stream->Status = IOStreamStatus::Ready; + if (size == 0) { - if (!stream->Interface.Read) - { - Log(LogLevel::Error, LogCategory::Core, "Trying to read a writeonly IOStream"); - stream->Status = IOStreamStatus::WriteOnly; - return 0; - } - - stream->Status = IOStreamStatus::Ready; - if (size == 0) - { - return 0; - } - size_t bytes = stream->Interface.Read(stream->Data, ptr, size, &stream->Status); - if (bytes == 0 && stream->Status == IOStreamStatus::Ready) - { - // TODO: Detect error and do this stream->Status = IOStreamStatus::Error; - stream->Status = IOStreamStatus::EndOfFile; - } - return bytes; + return 0; } - - int64 IOSeek(NonNullPtr stream, int64 offset, IOStreamSeekPivot pivot) + size_t bytes = stream->Interface.Read(stream->Data, ptr, size, &stream->Status); + if (bytes == 0 && stream->Status == IOStreamStatus::Ready) { - if (!stream->Interface.Seek) + // TODO: Detect error and do this stream->Status = IOStreamStatus::Error; + stream->Status = IOStreamStatus::EndOfFile; + } + return bytes; +} + +int64 IOSeek(NonNullPtr stream, int64 offset, IOStreamSeekPivot pivot) +{ + if (!stream->Interface.Seek) + { + Log(LogLevel::Error, LogCategory::Core, "IOSeek: Stream interface cannot Seek"); + return -1; + } + return stream->Interface.Seek(stream->Data, offset, pivot); +} + +int64 IOSize(NonNullPtr stream) +{ + if (!stream->Interface.Size) + { + int64 pos = IOSeek(stream, 0, IOStreamSeekPivot::Current); + if (pos < 0) { - Log(LogLevel::Error, LogCategory::Core, "IOSeek: Stream interface cannot Seek"); return -1; } - return stream->Interface.Seek(stream->Data, offset, pivot); - } + int64 size = IOSeek(stream, 0, IOStreamSeekPivot::End); - int64 IOSize(NonNullPtr stream) + IOSeek(stream, pos, IOStreamSeekPivot::Begin); + return size; + } + return stream->Interface.Size(stream->Data); +} + +ByteBuffer LoadFile(NonNullPtr arena, String filename) +{ + IOStream* stream = IOFromFile(arena, filename, WrapString("rb")); + if (!stream) { - if (!stream->Interface.Size) + return {}; + } + return LoadFile(arena, stream, true); +} + +ByteBuffer LoadFile(NonNullPtr arena, NonNullPtr stream, bool closeStreamWhenDone) +{ + constexpr size_t kFileChunkSize = 1024; + + auto deferred = Defer( + [&]() { - int64 pos = IOSeek(stream, 0, IOStreamSeekPivot::Current); - if (pos < 0) + if (closeStreamWhenDone) { - return -1; + IOClose(stream); } - int64 size = IOSeek(stream, 0, IOStreamSeekPivot::End); + }); - IOSeek(stream, pos, IOStreamSeekPivot::Begin); - return size; - } - return stream->Interface.Size(stream->Data); + // Try reading the size from the stream, if failing we'll try to read it chunk by chunk + bool loadChunks = false; + int64 ssize = IOSize(stream); + if (ssize < 0) + { + ssize = kFileChunkSize; + loadChunks = true; + } + size_t size = static_cast(ssize); + uint8* data = ArenaPushArray(arena, size + 1); + if (!data) + { + return {}; } - ByteBuffer LoadFile(NonNullPtr arena, String filename) + size_t totalSize = 0; + while (true) { - IOStream* stream = IOFromFile(arena, filename, WrapString("rb")); - if (!stream) + if (loadChunks) { - return {}; - } - return LoadFile(arena, stream, true); - } - - ByteBuffer LoadFile(NonNullPtr arena, NonNullPtr stream, bool closeStreamWhenDone) - { - constexpr size_t kFileChunkSize = 1024; - - auto deferred = Defer( - [&]() + if ((totalSize + kFileChunkSize) > size) { - if (closeStreamWhenDone) + size = totalSize + kFileChunkSize; + + // Not enough space, add some + uint8* newSpace = ArenaPushArray(arena, kFileChunkSize); + if (!newSpace) { - IOClose(stream); - } - }); - - // Try reading the size from the stream, if failing we'll try to read it chunk by chunk - bool loadChunks = false; - int64 ssize = IOSize(stream); - if (ssize < 0) - { - ssize = kFileChunkSize; - loadChunks = true; - } - size_t size = static_cast(ssize); - uint8* data = ArenaPushArray(arena, size + 1); - if (!data) - { - return {}; - } - - size_t totalSize = 0; - while (true) - { - if (loadChunks) - { - if ((totalSize + kFileChunkSize) > size) - { - size = totalSize + kFileChunkSize; - - // Not enough space, add some - uint8* newSpace = ArenaPushArray(arena, kFileChunkSize); - if (!newSpace) - { - return {}; - } + return {}; } } - - size_t sizeRead = IORead(stream, data + totalSize, (size - totalSize)); - if (sizeRead > 0) - { - totalSize += sizeRead; - continue; - } - if (stream->Status == IOStreamStatus::NotReady) - { - // Wait for the stream to be ready - wait_ms(1); - continue; - } - - // The stream status will remain set for the caller to check - break; } - // Adding null terminator - data[totalSize] = '\0'; - - ByteBuffer resultBuffer = {}; - resultBuffer.Data = reinterpret_cast(data); - resultBuffer.Size = totalSize; - return resultBuffer; - } - - bool IOClose(NonNullPtr stream) - { - bool result = true; - if (stream->Interface.Close) + size_t sizeRead = IORead(stream, data + totalSize, (size - totalSize)); + if (sizeRead > 0) { - result = stream->Interface.Close(stream->Data); + totalSize += sizeRead; + continue; } - return result; + if (stream->Status == IOStreamStatus::NotReady) + { + // Wait for the stream to be ready + wait_ms(1); + continue; + } + + // The stream status will remain set for the caller to check + break; } -} // namespace Juliet + // Adding null terminator + data[totalSize] = '\0'; + + ByteBuffer resultBuffer = {}; + resultBuffer.Data = reinterpret_cast(data); + resultBuffer.Size = totalSize; + return resultBuffer; +} + +bool IOClose(NonNullPtr stream) +{ + bool result = true; + if (stream->Interface.Close) + { + result = stream->Interface.Close(stream->Data); + } + return result; +} + diff --git a/Juliet/src/Core/HAL/IO/IOStream_cpp.h b/Juliet/src/Core/HAL/IO/IOStream_cpp.h index 6fdfb89..49b8ffc 100644 --- a/Juliet/src/Core/HAL/IO/IOStream_cpp.h +++ b/Juliet/src/Core/HAL/IO/IOStream_cpp.h @@ -1,19 +1,16 @@ -#pragma once +#pragma once #include #include -namespace Juliet +struct IOStream { - struct IOStream - { - IOStreamInterface Interface; - IOStreamDataPayload* Data; - IOStreamStatus Status; - }; -} // namespace Juliet + IOStreamInterface Interface; + IOStreamDataPayload* Data; + IOStreamStatus Status; +}; -namespace Juliet::Internal +namespace Internal { IOStream* IOFromFile(NonNullPtr arena, String filename, String mode); -} // namespace Juliet::Internal +} // namespace Internal diff --git a/Juliet/src/Core/HAL/IO/Win32/Win32IOStream.cpp b/Juliet/src/Core/HAL/IO/Win32/Win32IOStream.cpp index 201d453..39d3dcc 100644 --- a/Juliet/src/Core/HAL/IO/Win32/Win32IOStream.cpp +++ b/Juliet/src/Core/HAL/IO/Win32/Win32IOStream.cpp @@ -1,11 +1,11 @@ -#include +#include #include #include #include #include #include -namespace Juliet::Internal +namespace Internal { namespace { @@ -274,4 +274,4 @@ namespace Juliet::Internal } return stream; } -} // namespace Juliet::Internal +} // namespace Internal diff --git a/Juliet/src/Core/HAL/OS/OS.cpp b/Juliet/src/Core/HAL/OS/OS.cpp index d795b2d..cbf2c42 100644 --- a/Juliet/src/Core/HAL/OS/OS.cpp +++ b/Juliet/src/Core/HAL/OS/OS.cpp @@ -1,79 +1,76 @@ -#include +#include #include #include -namespace Juliet +namespace Memory { - namespace Memory + Byte* OS_Reserve(size_t size) { - Byte* OS_Reserve(size_t size) - { - return Internal::OS_Reserve(size); - } - - bool OS_Commit(Byte* ptr, size_t size) - { - return Internal::OS_Commit(ptr, size); - } - - void OS_Release(Byte* ptr, size_t size) - { - Internal::OS_Release(ptr, size); - } - } // namespace Memory - - namespace Time - { - namespace - { - float DeltaTime = 0.0f; - uint64 Frame = 0; - } // namespace - - uint64 Timestamp() - { - return Internal::OS_Timestamp(); - } - - void ComputeDeltaTime() - { - DeltaTime = Internal::OS_ComputeDeltaTime(); - ++Frame; - } - - float GetDeltaTime() - { - return DeltaTime; - } - - uint64 GetFrameNumber() - { - return Frame; - } - } // namespace Time - - namespace Debug - { - bool IsDebuggerPresent() - { - return Internal::IsDebuggerPresent(); - } - } // namespace Debug - - int Bootstrap(EntryPointFunc entryPointFunc, int argc, wchar_t** argv) - { - - int result = Internal::OS_Main(argc, argv); - if (result == 0) - { - set_thread_name(WrapString("main_thread")); - - result = entryPointFunc(argc, argv); - } - - Internal::OS_Main_Exit(); - - return result; + return Internal::OS_Reserve(size); } -} // namespace Juliet + bool OS_Commit(Byte* ptr, size_t size) + { + return Internal::OS_Commit(ptr, size); + } + + void OS_Release(Byte* ptr, size_t size) + { + Internal::OS_Release(ptr, size); + } +} // namespace Memory + +namespace Time +{ + namespace + { + float DeltaTime = 0.0f; + uint64 Frame = 0; + } // namespace + + uint64 Timestamp() + { + return Internal::OS_Timestamp(); + } + + void ComputeDeltaTime() + { + DeltaTime = Internal::OS_ComputeDeltaTime(); + ++Frame; + } + + float GetDeltaTime() + { + return DeltaTime; + } + + uint64 GetFrameNumber() + { + return Frame; + } +} // namespace Time + +namespace Debug +{ + bool IsDebuggerPresent() + { + return Internal::IsDebuggerPresent(); + } +} // namespace Debug + +int Bootstrap(EntryPointFunc entryPointFunc, int argc, wchar_t** argv) +{ + + int result = Internal::OS_Main(argc, argv); + if (result == 0) + { + set_thread_name(WrapString("main_thread")); + + result = entryPointFunc(argc, argv); + } + + Internal::OS_Main_Exit(); + + return result; +} + diff --git a/Juliet/src/Core/HAL/OS/OS_Private.h b/Juliet/src/Core/HAL/OS/OS_Private.h index 6bdd625..a4f0586 100644 --- a/Juliet/src/Core/HAL/OS/OS_Private.h +++ b/Juliet/src/Core/HAL/OS/OS_Private.h @@ -1,28 +1,25 @@ -#pragma once +#pragma once -namespace Juliet +namespace Memory::Internal { - namespace Memory::Internal - { - Byte* OS_Reserve(size_t size); - bool OS_Commit(Byte* ptr, size_t size); - void OS_Release(Byte* ptr, size_t size); - } // namespace Memory::Internal + Byte* OS_Reserve(size_t size); + bool OS_Commit(Byte* ptr, size_t size); + void OS_Release(Byte* ptr, size_t size); +} // namespace Memory::Internal - namespace Debug::Internal - { - bool IsDebuggerPresent(); - } // namespace Debug::Internal +namespace Debug::Internal +{ + bool IsDebuggerPresent(); +} // namespace Debug::Internal - namespace Time::Internal - { - uint64 OS_Timestamp(); - float OS_ComputeDeltaTime(); - } // namespace Time::Internal +namespace Time::Internal +{ + uint64 OS_Timestamp(); + float OS_ComputeDeltaTime(); +} // namespace Time::Internal - namespace Internal - { - int OS_Main(int argc, wchar_t** argv); - void OS_Main_Exit(); - } // namespace Internal -} // namespace Juliet +namespace Internal +{ + int OS_Main(int argc, wchar_t** argv); + void OS_Main_Exit(); +} // namespace Internal diff --git a/Juliet/src/Core/HAL/OS/Win32/Win32OS.cpp b/Juliet/src/Core/HAL/OS/Win32/Win32OS.cpp index e19febf..2d94758 100644 --- a/Juliet/src/Core/HAL/OS/Win32/Win32OS.cpp +++ b/Juliet/src/Core/HAL/OS/Win32/Win32OS.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -8,141 +8,138 @@ #include #include -namespace Juliet +Win32_SetThreadDescription_FuncType* Win32_SetThreadDescription_Func = nullptr; + +namespace { - Win32_SetThreadDescription_FuncType* Win32_SetThreadDescription_Func = nullptr; + RIO_EXTENSION_FUNCTION_TABLE w32_rio_functions = {}; +} // namespace - namespace +namespace Memory::Internal +{ + Byte* OS_Reserve(size_t size) { - RIO_EXTENSION_FUNCTION_TABLE w32_rio_functions = {}; - } // namespace + auto* result = static_cast(VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE)); + return result; + } - namespace Memory::Internal + bool OS_Commit(Byte* ptr, size_t size) { - Byte* OS_Reserve(size_t size) + bool result = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != nullptr); + + Assert(size <= static_cast(MaxValueOf())); + + if (w32_rio_functions.RIORegisterBuffer != nullptr && w32_rio_functions.RIODeregisterBuffer != nullptr) { - auto* result = static_cast(VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE)); - return result; + w32_rio_functions.RIODeregisterBuffer( + w32_rio_functions.RIORegisterBuffer(reinterpret_cast(ptr), static_cast(size))); } - bool OS_Commit(Byte* ptr, size_t size) - { - bool result = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != nullptr); + return result; + } - Assert(size <= static_cast(MaxValueOf())); - - if (w32_rio_functions.RIORegisterBuffer != nullptr && w32_rio_functions.RIODeregisterBuffer != nullptr) - { - w32_rio_functions.RIODeregisterBuffer( - w32_rio_functions.RIORegisterBuffer(reinterpret_cast(ptr), static_cast(size))); - } - - return result; - } - - void OS_Release(Byte* ptr, size_t size) - { - // size not used on windows - std::ignore = size; - - VirtualFree(ptr, 0, MEM_RELEASE); - } - } // namespace Memory::Internal - - namespace Time::Internal + void OS_Release(Byte* ptr, size_t size) { - uint64 OS_Timestamp() - { - FILETIME ft; - GetSystemTimeAsFileTime(&ft); + // size not used on windows + std::ignore = size; - return (static_cast(ft.dwHighDateTime) << 32) + ft.dwLowDateTime; - } + VirtualFree(ptr, 0, MEM_RELEASE); + } +} // namespace Memory::Internal - float OS_ComputeDeltaTime() - { - static LARGE_INTEGER frequency = {}; - static LARGE_INTEGER lastTime = {}; - if (frequency.QuadPart == 0) - { - QueryPerformanceFrequency(&frequency); - QueryPerformanceCounter(&lastTime); - } - - LARGE_INTEGER currentTime; - QueryPerformanceCounter(¤tTime); - const float deltaTime = - static_cast(currentTime.QuadPart - lastTime.QuadPart) / static_cast(frequency.QuadPart); - lastTime = currentTime; - - return deltaTime; - } - - } // namespace Time::Internal - - namespace Debug::Internal +namespace Time::Internal +{ + uint64 OS_Timestamp() { - bool IsDebuggerPresent() - { - return ::IsDebuggerPresent(); - } - } // namespace Debug::Internal + FILETIME ft; + GetSystemTimeAsFileTime(&ft); - namespace + return (static_cast(ft.dwHighDateTime) << 32) + ft.dwLowDateTime; + } + + float OS_ComputeDeltaTime() { - // Used to handle a crash/exception - LONG WINAPI ExceptionFilter(EXCEPTION_POINTERS* exceptionPtrs) + static LARGE_INTEGER frequency = {}; + static LARGE_INTEGER lastTime = {}; + if (frequency.QuadPart == 0) { - (void)exceptionPtrs; - // See for more info https://github.com/EpicGamesExt/raddebugger/blob/master/src/os/core/win32/os_core_win32.c - ExitProcess(1); + QueryPerformanceFrequency(&frequency); + QueryPerformanceCounter(&lastTime); } - } // namespace - namespace Internal + LARGE_INTEGER currentTime; + QueryPerformanceCounter(¤tTime); + const float deltaTime = + static_cast(currentTime.QuadPart - lastTime.QuadPart) / static_cast(frequency.QuadPart); + lastTime = currentTime; + + return deltaTime; + } + +} // namespace Time::Internal + +namespace Debug::Internal +{ + bool IsDebuggerPresent() { - thread_local thread_context* mainThread = nullptr; + return ::IsDebuggerPresent(); + } +} // namespace Debug::Internal - int OS_Main([[maybe_unused]] int argc, [[maybe_unused]] wchar_t** argv) +namespace +{ + // Used to handle a crash/exception + LONG WINAPI ExceptionFilter(EXCEPTION_POINTERS* exceptionPtrs) + { + (void)exceptionPtrs; + // See for more info https://github.com/EpicGamesExt/raddebugger/blob/master/src/os/core/win32/os_core_win32.c + ExitProcess(1); + } +} // namespace + +namespace Internal +{ + thread_local thread_context* mainThread = nullptr; + + int OS_Main([[maybe_unused]] int argc, [[maybe_unused]] wchar_t** argv) + { + SetUnhandledExceptionFilter(&ExceptionFilter); + + // Allow only one instance to be launched. + CreateMutex(nullptr, false, L"Local\\Juliet.App"); + if (GetLastError() == ERROR_ALREADY_EXISTS) { - SetUnhandledExceptionFilter(&ExceptionFilter); - - // Allow only one instance to be launched. - CreateMutex(nullptr, false, L"Local\\Juliet.App"); - if (GetLastError() == ERROR_ALREADY_EXISTS) - { - MessageBox(nullptr, L"An instance of Juliet is already running.", L"Juliet", MB_OK | MB_ICONEXCLAMATION); - return EXIT_FAILURE; - } - - // Get some kernel32 functions - auto dynLib = LoadDynamicLibrary("kernel32.dll"); - Win32_SetThreadDescription_Func = - (Win32_SetThreadDescription_FuncType*)LoadFunction(dynLib, "SetThreadDescription"); - - // Create a dummy socket to access RIO functions. Those will be used to do fine memory management - { - WSADATA WinSockData; - WSAStartup(MAKEWORD(2, 2), &WinSockData); - GUID guid = WSAID_MULTIPLE_RIO; - DWORD rio_byte = 0; - SOCKET Sock = socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); - WSAIoctl(Sock, SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), - reinterpret_cast(&w32_rio_functions), sizeof(w32_rio_functions), &rio_byte, nullptr, nullptr); - closesocket(Sock); - } - - mainThread = thread_context_alloc(); - thread_context_select(mainThread); - - return 0; + MessageBox(nullptr, L"An instance of Juliet is already running.", L"Juliet", MB_OK | MB_ICONEXCLAMATION); + return EXIT_FAILURE; } - void OS_Main_Exit() + // Get some kernel32 functions + auto dynLib = LoadDynamicLibrary("kernel32.dll"); + Win32_SetThreadDescription_Func = + (Win32_SetThreadDescription_FuncType*)LoadFunction(dynLib, "SetThreadDescription"); + + // Create a dummy socket to access RIO functions. Those will be used to do fine memory management { - Assert(mainThread); - thread_context_release(mainThread); - mainThread = nullptr; + WSADATA WinSockData; + WSAStartup(MAKEWORD(2, 2), &WinSockData); + GUID guid = WSAID_MULTIPLE_RIO; + DWORD rio_byte = 0; + SOCKET Sock = socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); + WSAIoctl(Sock, SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), + reinterpret_cast(&w32_rio_functions), sizeof(w32_rio_functions), &rio_byte, nullptr, nullptr); + closesocket(Sock); } - } // namespace Internal -} // namespace Juliet + + mainThread = thread_context_alloc(); + thread_context_select(mainThread); + + return 0; + } + + void OS_Main_Exit() + { + Assert(mainThread); + thread_context_release(mainThread); + mainThread = nullptr; + } +} // namespace Internal diff --git a/Juliet/src/Core/HotReload/HotReload.cpp b/Juliet/src/Core/HotReload/HotReload.cpp index 919d6db..7cda30d 100644 --- a/Juliet/src/Core/HotReload/HotReload.cpp +++ b/Juliet/src/Core/HotReload/HotReload.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -7,64 +7,61 @@ #define MAX_TRIES 100 -namespace Juliet +void InitHotReloadCode(NonNullPtr arena, HotReloadCode& code, String dllName, String transientDllName, String lockFilename) { - void InitHotReloadCode(NonNullPtr arena, HotReloadCode& code, String dllName, String transientDllName, String lockFilename) + // Get the app base path and build the dll path from there. + String basePath = GetBasePath(); + size_t basePathLength = StringLength(basePath); + + // Assign Transient dll path + code.TransientDLLName = transientDllName; + + // First allocate all the full path. + // TODO: Add path composition into filesystem + string format + string builder + const size_t dllFullPathLength = + basePathLength + StringLength(dllName) + 1; // Need +1 because snprintf needs 0 terminated strings + + code.DLLFullPath.Str = static_cast( + 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)); + if (writtenSize < static_cast(dllFullPathLength) - 1) { - // Get the app base path and build the dll path from there. - String basePath = GetBasePath(); - size_t basePathLength = StringLength(basePath); - - // Assign Transient dll path - code.TransientDLLName = transientDllName; - - // First allocate all the full path. - // TODO: Add path composition into filesystem + string format + string builder - const size_t dllFullPathLength = - basePathLength + StringLength(dllName) + 1; // Need +1 because snprintf needs 0 terminated strings - - code.DLLFullPath.Str = static_cast( - 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)); - if (writtenSize < static_cast(dllFullPathLength) - 1) - { - Log(LogLevel::Error, LogCategory::Core, "Cannot create DLL Full Path"); - return; - } - code.DLLFullPath.Size = static_cast(writtenSize); - - // Lock filename path - const size_t lockPathLength = - basePathLength + StringLength(lockFilename) + 1; // Need +1 because snprintf needs 0 terminated strings - code.LockFullPath.Str = static_cast( - 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)); - if (writtenSize < static_cast(lockPathLength) - 1) - { - code.LockFullPath.Size = 0; - Log(LogLevel::Error, LogCategory::Core, "Cannot create lock file full path"); - return; - } - code.LockFullPath.Size = static_cast(writtenSize); - - LoadCode(code); + Log(LogLevel::Error, LogCategory::Core, "Cannot create DLL Full Path"); + return; } + code.DLLFullPath.Size = static_cast(writtenSize); - void ShutdownHotReloadCode(HotReloadCode& code) + // Lock filename path + const size_t lockPathLength = + basePathLength + StringLength(lockFilename) + 1; // Need +1 because snprintf needs 0 terminated strings + code.LockFullPath.Str = static_cast( + 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)); + if (writtenSize < static_cast(lockPathLength) - 1) { - UnloadCode(code); - - code.DLLFullPath.Size = 0; code.LockFullPath.Size = 0; + Log(LogLevel::Error, LogCategory::Core, "Cannot create lock file full path"); + return; } + code.LockFullPath.Size = static_cast(writtenSize); - void ReloadCode(HotReloadCode& code) + LoadCode(code); +} + +void ShutdownHotReloadCode(HotReloadCode& code) +{ + UnloadCode(code); + + code.DLLFullPath.Size = 0; + code.LockFullPath.Size = 0; +} + +void ReloadCode(HotReloadCode& code) +{ + UnloadCode(code); + for (uint32 tryItr = 0; !code.IsValid && tryItr < MAX_TRIES; ++tryItr) { - UnloadCode(code); - for (uint32 tryItr = 0; !code.IsValid && tryItr < MAX_TRIES; ++tryItr) - { - LoadCode(code); - wait_ms(100); - } + LoadCode(code); + wait_ms(100); } -} // namespace Juliet +} diff --git a/Juliet/src/Core/HotReload/Win32/Win32HotReload.cpp b/Juliet/src/Core/HotReload/Win32/Win32HotReload.cpp index 5e54d79..f8a606a 100644 --- a/Juliet/src/Core/HotReload/Win32/Win32HotReload.cpp +++ b/Juliet/src/Core/HotReload/Win32/Win32HotReload.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -8,143 +8,140 @@ #include #include -namespace Juliet +namespace { - namespace + FILETIME GetLastWriteTime(const char* filename) { - FILETIME GetLastWriteTime(const char* filename) + FILETIME lastWriteTime = {}; + + WIN32_FILE_ATTRIBUTE_DATA Data; + if (GetFileAttributesExA(filename, GetFileExInfoStandard, &Data)) { - FILETIME lastWriteTime = {}; - - WIN32_FILE_ATTRIBUTE_DATA Data; - if (GetFileAttributesExA(filename, GetFileExInfoStandard, &Data)) - { - lastWriteTime = Data.ftLastWriteTime; - } - - return lastWriteTime; + lastWriteTime = Data.ftLastWriteTime; } - constexpr size_t kMaxAttempts = 256; - constexpr size_t kMaxDLLID = 256; - constexpr size_t kTempDLLBufferSizeForID = 5; // Max ID numbers - } // namespace + return lastWriteTime; + } - void LoadCode(HotReloadCode& code) + constexpr size_t kMaxAttempts = 256; + constexpr size_t kMaxDLLID = 256; + constexpr size_t kTempDLLBufferSizeForID = 5; // Max ID numbers +} // namespace + +void LoadCode(HotReloadCode& code) +{ + char* lockFilename = code.LockFullPath.Str; + WIN32_FILE_ATTRIBUTE_DATA Ignored; + if (!GetFileAttributesExA(lockFilename, GetFileExInfoStandard, &Ignored)) { - char* lockFilename = code.LockFullPath.Str; - WIN32_FILE_ATTRIBUTE_DATA Ignored; - if (!GetFileAttributesExA(lockFilename, GetFileExInfoStandard, &Ignored)) + const char* dllName = code.DLLFullPath.Str; + + FILETIME lastWriteTime = GetLastWriteTime(dllName); + ULARGE_INTEGER result{ .LowPart = lastWriteTime.dwLowDateTime, .HighPart = lastWriteTime.dwHighDateTime }; + code.LastWriteTime = result.QuadPart; + + // Create filename for the temp dll until we find a valid id. + // This is not infinite, in a big session we could reach the 128 attempts and fail... + // We'll see for better later. + + // Get the app base path and build the dll path from there. + String basePath = GetBasePath(); + size_t basePathLength = StringLength(basePath); + + const size_t tempDllMaxBufferSize = + basePathLength + StringLength(code.TransientDLLName) + /* _ */ 1 + kTempDLLBufferSizeForID + 1 /* \0 */; + + // Allocate from Scratch Arena (transient) + TempArena temp = scratch_begin(0, 0); + auto tempDllPath = ArenaPushArray(temp.Arena, tempDllMaxBufferSize); + + for (uint32 attempt = 0; attempt < kMaxAttempts; ++attempt) { - const char* dllName = code.DLLFullPath.Str; - - FILETIME lastWriteTime = GetLastWriteTime(dllName); - ULARGE_INTEGER result{ .LowPart = lastWriteTime.dwLowDateTime, .HighPart = lastWriteTime.dwHighDateTime }; - code.LastWriteTime = result.QuadPart; - - // Create filename for the temp dll until we find a valid id. - // This is not infinite, in a big session we could reach the 128 attempts and fail... - // We'll see for better later. - - // Get the app base path and build the dll path from there. - String basePath = GetBasePath(); - size_t basePathLength = StringLength(basePath); - - const size_t tempDllMaxBufferSize = - basePathLength + StringLength(code.TransientDLLName) + /* _ */ 1 + kTempDLLBufferSizeForID + 1 /* \0 */; - - // Allocate from Scratch Arena (transient) - TempArena temp = scratch_begin(0, 0); - auto tempDllPath = ArenaPushArray(temp.Arena, tempDllMaxBufferSize); - - for (uint32 attempt = 0; attempt < kMaxAttempts; ++attempt) + // int to char + char idToStr[kTempDLLBufferSizeForID + 1]; + int idLength = snprintf(idToStr, sizeof(idToStr), "%u", code.UniqueID); + if (idLength < 0) { - // int to char - char idToStr[kTempDLLBufferSizeForID + 1]; - int idLength = snprintf(idToStr, sizeof(idToStr), "%u", code.UniqueID); - if (idLength < 0) - { - // Scratch memory, no free needed - Log(LogLevel::Error, LogCategory::Core, "Cannot create temp full path"); - return; - } + // Scratch memory, no free needed + Log(LogLevel::Error, LogCategory::Core, "Cannot create temp full path"); + return; + } - int writtenSize = snprintf(tempDllPath, tempDllMaxBufferSize, "%s%s_%s", CStr(basePath), idToStr, - CStr(code.TransientDLLName)); - if (writtenSize < 0) - { - // Scratch memory, no free needed - Log(LogLevel::Error, LogCategory::Core, "Cannot create temp full path"); - return; - } + int writtenSize = snprintf(tempDllPath, tempDllMaxBufferSize, "%s%s_%s", CStr(basePath), idToStr, + CStr(code.TransientDLLName)); + if (writtenSize < 0) + { + // Scratch memory, no free needed + Log(LogLevel::Error, LogCategory::Core, "Cannot create temp full path"); + return; + } - if (static_cast(writtenSize) + 1 < - basePathLength + static_cast(idLength) + code.TransientDLLName.Size) - { - // Scratch memory, no free needed - Log(LogLevel::Error, LogCategory::Core, "Cannot create temp full path"); - return; - } + if (static_cast(writtenSize) + 1 < + basePathLength + static_cast(idLength) + code.TransientDLLName.Size) + { + // Scratch memory, no free needed + Log(LogLevel::Error, LogCategory::Core, "Cannot create temp full path"); + return; + } - if (++code.UniqueID >= kMaxDLLID) + if (++code.UniqueID >= kMaxDLLID) + { + code.UniqueID = 0; + } + if (CopyFileA(dllName, tempDllPath, false)) + { + break; + } + } + scratch_end(temp); + + code.Dll = LoadDynamicLibrary(tempDllPath); + if (code.Dll) + { + code.IsValid = true; + for (size_t FunctionIndex = 0; FunctionIndex < code.FunctionCount; ++FunctionIndex) + { + if (auto function = reinterpret_cast(LoadFunction(code.Dll, code.FunctionNames[FunctionIndex]))) { - code.UniqueID = 0; + code.Functions[FunctionIndex] = function; } - if (CopyFileA(dllName, tempDllPath, false)) + else { + code.IsValid = false; break; } } - scratch_end(temp); - - code.Dll = LoadDynamicLibrary(tempDllPath); - if (code.Dll) - { - code.IsValid = true; - for (size_t FunctionIndex = 0; FunctionIndex < code.FunctionCount; ++FunctionIndex) - { - if (auto function = reinterpret_cast(LoadFunction(code.Dll, code.FunctionNames[FunctionIndex]))) - { - code.Functions[FunctionIndex] = function; - } - else - { - code.IsValid = false; - break; - } - } - } - } - - if (!code.IsValid) - { - UnloadCode(code); } } - void UnloadCode(HotReloadCode& code) + if (!code.IsValid) { - code.IsValid = false; - if (code.Dll) - { - UnloadDynamicLibrary(code.Dll); - } - code.Dll = nullptr; - - code.LastWriteTime = 0; - ZeroDynArray(code.FunctionCount, code.Functions); + UnloadCode(code); } +} - bool ShouldReloadCode(const HotReloadCode& code) +void UnloadCode(HotReloadCode& code) +{ + code.IsValid = false; + if (code.Dll) { - ULARGE_INTEGER largeInt = {}; - FILETIME codeLastWriteTime = {}; - largeInt.QuadPart = code.LastWriteTime; - codeLastWriteTime.dwHighDateTime = largeInt.HighPart; - codeLastWriteTime.dwLowDateTime = largeInt.LowPart; - - FILETIME lastWriteTime = GetLastWriteTime(code.DLLFullPath.Str); - int compare = CompareFileTime(&lastWriteTime, &codeLastWriteTime); - return compare != 0; + UnloadDynamicLibrary(code.Dll); } -} // namespace Juliet + code.Dll = nullptr; + + code.LastWriteTime = 0; + ZeroDynArray(code.FunctionCount, code.Functions); +} + +bool ShouldReloadCode(const HotReloadCode& code) +{ + ULARGE_INTEGER largeInt = {}; + FILETIME codeLastWriteTime = {}; + largeInt.QuadPart = code.LastWriteTime; + codeLastWriteTime.dwHighDateTime = largeInt.HighPart; + codeLastWriteTime.dwLowDateTime = largeInt.LowPart; + + FILETIME lastWriteTime = GetLastWriteTime(code.DLLFullPath.Str); + int compare = CompareFileTime(&lastWriteTime, &codeLastWriteTime); + return compare != 0; +} diff --git a/Juliet/src/Core/ImGui/ImGuiService.cpp b/Juliet/src/Core/ImGui/ImGuiService.cpp index 3702aae..b01703d 100644 --- a/Juliet/src/Core/ImGui/ImGuiService.cpp +++ b/Juliet/src/Core/ImGui/ImGuiService.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -12,7 +12,7 @@ extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); -namespace Juliet::ImGuiService +namespace ImGuiService { namespace { @@ -133,8 +133,8 @@ namespace Juliet::ImGuiService void RunTests() { printf("ImGuiService: Running Unit Tests...\n"); - Juliet::UnitTest::TestImGui(); + UnitTest::TestImGui(); } -} // namespace Juliet::ImGuiService +} // namespace ImGuiService #endif // JULIET_ENABLE_IMGUI diff --git a/Juliet/src/Core/ImGui/ImGuiTests.cpp b/Juliet/src/Core/ImGui/ImGuiTests.cpp index 691d85f..62ee771 100644 --- a/Juliet/src/Core/ImGui/ImGuiTests.cpp +++ b/Juliet/src/Core/ImGui/ImGuiTests.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -6,7 +6,7 @@ #include #include -namespace Juliet::UnitTest +namespace UnitTest { void TestImGui() { @@ -71,4 +71,4 @@ namespace Juliet::UnitTest printf("ImGui tests passed (Exhaustive).\n"); #endif } -} // namespace Juliet::UnitTest +} // namespace UnitTest diff --git a/Juliet/src/Core/Juliet.cpp b/Juliet/src/Core/Juliet.cpp index 775715d..6cc4b9a 100644 --- a/Juliet/src/Core/Juliet.cpp +++ b/Juliet/src/Core/Juliet.cpp @@ -1,61 +1,58 @@ -#include +#include #include #include #include #include -namespace Juliet +namespace { - namespace + bool IsQuitting = false; + uint8 SystemInitRefCount[ToUnderlying(JulietInit_Flags::Count)]; + + void IncrementSystemRefCount(JulietInit_Flags flag) { - bool IsQuitting = false; - uint8 SystemInitRefCount[ToUnderlying(JulietInit_Flags::Count)]; + Assert(flag != JulietInit_Flags::None); + ++SystemInitRefCount[ToUnderlying(flag)]; + } - void IncrementSystemRefCount(JulietInit_Flags flag) - { - Assert(flag != JulietInit_Flags::None); - ++SystemInitRefCount[ToUnderlying(flag)]; - } - - void DecrementSystemRefCount(JulietInit_Flags flag) - { - Assert(flag != JulietInit_Flags::None); - Assert(SystemInitRefCount[ToUnderlying(flag)] != 0 && "Trying to decrement ref count but its already 0"); - - if (IsQuitting) - { - SystemInitRefCount[ToUnderlying(flag)] = 0; - } - else - { - --SystemInitRefCount[ToUnderlying(flag)]; - } - } - - bool IsInitialized(JulietInit_Flags flag) - { - return SystemInitRefCount[ToUnderlying(flag)] != 0; - } - } // namespace - - void JulietInit(JulietInit_Flags flags) + void DecrementSystemRefCount(JulietInit_Flags flag) { - // Optional systems - if ((flags & JulietInit_Flags::Display) != JulietInit_Flags::None) + Assert(flag != JulietInit_Flags::None); + Assert(SystemInitRefCount[ToUnderlying(flag)] != 0 && "Trying to decrement ref count but its already 0"); + + if (IsQuitting) { - InitializeDisplaySystem(); - IncrementSystemRefCount(JulietInit_Flags::Display); + SystemInitRefCount[ToUnderlying(flag)] = 0; + } + else + { + --SystemInitRefCount[ToUnderlying(flag)]; } } - void JulietShutdown() + bool IsInitialized(JulietInit_Flags flag) { - IsQuitting = true; - if (IsInitialized(JulietInit_Flags::Display)) - { - DecrementSystemRefCount(JulietInit_Flags::Display); - ShutdownDisplaySystem(); - } + return SystemInitRefCount[ToUnderlying(flag)] != 0; } +} // namespace + +void JulietInit(JulietInit_Flags flags) +{ + // Optional systems + if ((flags & JulietInit_Flags::Display) != JulietInit_Flags::None) + { + InitializeDisplaySystem(); + IncrementSystemRefCount(JulietInit_Flags::Display); + } +} + +void JulietShutdown() +{ + IsQuitting = true; + if (IsInitialized(JulietInit_Flags::Display)) + { + DecrementSystemRefCount(JulietInit_Flags::Display); + ShutdownDisplaySystem(); + } +} -} // namespace Juliet diff --git a/Juliet/src/Core/Logging/LogManager.cpp b/Juliet/src/Core/Logging/LogManager.cpp index 6c21644..c827629 100644 --- a/Juliet/src/Core/Logging/LogManager.cpp +++ b/Juliet/src/Core/Logging/LogManager.cpp @@ -1,4 +1,4 @@ -#include +#include #include #ifdef global @@ -23,191 +23,188 @@ // TODO Juliet chrono -namespace Juliet +namespace { - namespace + struct LogsEntry : public QueueNode { - struct LogsEntry : public QueueNode - { - String Value; - std::chrono::system_clock::time_point Time; - LogLevel Level; - LogCategory Category; - }; - DECLARE_QUEUE(LogsEntry); + String Value; + std::chrono::system_clock::time_point Time; + LogLevel Level; + LogCategory Category; + }; + DECLARE_QUEUE(LogsEntry); - // TODO: Debug level per category - const bool kPrintDebugLog = false; + // TODO: Debug level per category + const bool kPrintDebugLog = false; - // A log scope accumulates log until end of scope. - // Can be used to accumulate then write in a log file each frame. - struct LogScope - { - LogScope* Next; - size_t Position; - LogsEntryQueue Entries; - }; + // A log scope accumulates log until end of scope. + // Can be used to accumulate then write in a log file each frame. + struct LogScope + { + LogScope* Next; + size_t Position; + LogsEntryQueue Entries; + }; - // Logs contains the current scopes and the arena - struct Logs - { - Arena* Arena = nullptr; - LogScope* TopScope = nullptr; - }; + // Logs contains the current scopes and the arena + struct Logs + { + Arena* Arena = nullptr; + LogScope* TopScope = nullptr; + }; - Logs* ActiveLog = nullptr; + Logs* ActiveLog = nullptr; - Logs* LogAllocate() - { - Arena* arena = ArenaAllocate({ .Name = "Log Manager" }); - Logs* logs = ArenaPushStruct(arena); - logs->Arena = arena; - return logs; - } + Logs* LogAllocate() + { + Arena* arena = ArenaAllocate({ .Name = "Log Manager" }); + Logs* logs = ArenaPushStruct(arena); + logs->Arena = arena; + return logs; + } - void LogRelease(NonNullPtr logs) - { - ArenaRelease(logs->Arena); - } + void LogRelease(NonNullPtr logs) + { + ArenaRelease(logs->Arena); + } - void OutputLog(LogsEntry& entry) - { - // TODO Juliet Output io for each platform + void OutputLog(LogsEntry& entry) + { + // TODO Juliet Output io for each platform - // {:%F} is YYYY-MM-DD, {:%T} is HH:MM:SS.ffffff - std::string timestamp = std::format("[{:%F %T}] ", entry.Time); - std::string fullMessage = timestamp + CStr(entry.Value) + "\n"; + // {:%F} is YYYY-MM-DD, {:%T} is HH:MM:SS.ffffff + std::string timestamp = std::format("[{:%F %T}] ", entry.Time); + std::string fullMessage = timestamp + CStr(entry.Value) + "\n"; #ifdef JULIET_WIN32 - OutputDebugStringA(fullMessage.c_str()); + OutputDebugStringA(fullMessage.c_str()); #endif - printf("%s", fullMessage.c_str()); - } + printf("%s", fullMessage.c_str()); + } - void PushLogEntry(NonNullPtr logs, String value, LogLevel level, LogCategory category) - { - Arena* arena = logs->Arena; - String str = StringCopy(arena, value); - - // Push onto the current scope - LogsEntry* newEntry = ArenaPushStruct(arena); - newEntry->Time = std::chrono::system_clock::now(); - newEntry->Level = level; - newEntry->Category = category; - newEntry->Value = str; - - Enqueue(logs->TopScope->Entries, newEntry); - logs->TopScope->Entries.Size += sizeof(LogsEntry) + str.Size; - - OutputLog(*newEntry); - } - } // namespace - - void InitializeLogManager() + void PushLogEntry(NonNullPtr logs, String value, LogLevel level, LogCategory category) { + Arena* arena = logs->Arena; + String str = StringCopy(arena, value); + + // Push onto the current scope + LogsEntry* newEntry = ArenaPushStruct(arena); + newEntry->Time = std::chrono::system_clock::now(); + newEntry->Level = level; + newEntry->Category = category; + newEntry->Value = str; + + Enqueue(logs->TopScope->Entries, newEntry); + logs->TopScope->Entries.Size += sizeof(LogsEntry) + str.Size; + + OutputLog(*newEntry); + } +} // namespace + +void InitializeLogManager() +{ #ifdef JULIET_WIN32 - SetConsoleOutputCP(CP_UTF8); - SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); + SetConsoleCP(CP_UTF8); #endif - ActiveLog = LogAllocate(); - LogScopeBegin(); + ActiveLog = LogAllocate(); + LogScopeBegin(); +} + +void ShutdownLogManager() +{ + LogScopeEnd(); + LogRelease(ActiveLog); +} + +void LogScopeBegin() +{ + Assert(ActiveLog != nullptr); + + size_t position = ArenaPos(ActiveLog->Arena); + LogScope* scope = ArenaPushStruct(ActiveLog->Arena); + scope->Position = position; + SingleLinkedListPushNext(ActiveLog->TopScope, scope); +} + +void LogScopeEnd() +{ + Assert(ActiveLog != nullptr); + + LogScope* scope = ActiveLog->TopScope; + Assert(scope != nullptr); + + SingleLinkedListPopNext(ActiveLog->TopScope); + + ArenaPopTo(ActiveLog->Arena, scope->Position); +} + +void Log(LogLevel level, LogCategory category, const char* fmt, va_list args) +{ + if (level == LogLevel::Debug && kPrintDebugLog == false) + { + return; } - void ShutdownLogManager() + // TODO : Revisit, copy from https://github.com/Eclmist/Ether/blob/develop/src/common/logging/loggingmanager.cpp + char formattedBuffer[4096]; + + (void)vsprintf_s(formattedBuffer, fmt, args); // Cast to void to ignore the return type. TODO : Juliet format function + + std::string formattedText(formattedBuffer); + + std::stringstream ss(formattedText); + std::string individualLine; + + while (std::getline(ss, individualLine, '\n')) { - LogScopeEnd(); - LogRelease(ActiveLog); - } - - void LogScopeBegin() - { - Assert(ActiveLog != nullptr); - - size_t position = ArenaPos(ActiveLog->Arena); - LogScope* scope = ArenaPushStruct(ActiveLog->Arena); - scope->Position = position; - SingleLinkedListPushNext(ActiveLog->TopScope, scope); - } - - void LogScopeEnd() - { - Assert(ActiveLog != nullptr); - - LogScope* scope = ActiveLog->TopScope; - Assert(scope != nullptr); - - SingleLinkedListPopNext(ActiveLog->TopScope); - - ArenaPopTo(ActiveLog->Arena, scope->Position); - } - - void Log(LogLevel level, LogCategory category, const char* fmt, va_list args) - { - if (level == LogLevel::Debug && kPrintDebugLog == false) + // Logs can happen before the active log is set, in that case, we can write to the console but not register the entry. + // One case is the Arena Allocate that calls logs and will happen before the logs are properly set because logs need to allocate an arena. + if (ActiveLog != nullptr) { - return; - } - - // TODO : Revisit, copy from https://github.com/Eclmist/Ether/blob/develop/src/common/logging/loggingmanager.cpp - char formattedBuffer[4096]; - - (void)vsprintf_s(formattedBuffer, fmt, args); // Cast to void to ignore the return type. TODO : Juliet format function - - std::string formattedText(formattedBuffer); - - std::stringstream ss(formattedText); - std::string individualLine; - - while (std::getline(ss, individualLine, '\n')) - { - // Logs can happen before the active log is set, in that case, we can write to the console but not register the entry. - // One case is the Arena Allocate that calls logs and will happen before the logs are properly set because logs need to allocate an arena. - if (ActiveLog != nullptr) - { - String julietstr = WrapString(individualLine.c_str()); - PushLogEntry(ActiveLog, julietstr, level, category); - } + String julietstr = WrapString(individualLine.c_str()); + PushLogEntry(ActiveLog, julietstr, level, category); } } +} - void Log(LogLevel level, LogCategory category, const char* fmt, ...) - { - va_list args; - va_start(args, fmt); - Log(level, category, fmt, args); - va_end(args); - } +void Log(LogLevel level, LogCategory category, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + Log(level, category, fmt, args); + va_end(args); +} - void LogDebug(LogCategory category, const char* fmt, ...) - { - va_list args; - va_start(args, fmt); - Log(LogLevel::Debug, category, fmt, args); - va_end(args); - } +void LogDebug(LogCategory category, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + Log(LogLevel::Debug, category, fmt, args); + va_end(args); +} - void LogMessage(LogCategory category, const char* fmt, ...) - { - va_list args; - va_start(args, fmt); - Log(LogLevel::Message, category, fmt, args); - va_end(args); - } +void LogMessage(LogCategory category, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + Log(LogLevel::Message, category, fmt, args); + va_end(args); +} - void LogWarning(LogCategory category, const char* fmt, ...) - { - va_list args; - va_start(args, fmt); - Log(LogLevel::Warning, category, fmt, args); - va_end(args); - } +void LogWarning(LogCategory category, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + Log(LogLevel::Warning, category, fmt, args); + va_end(args); +} - void LogError(LogCategory category, const char* fmt, ...) - { - va_list args; - va_start(args, fmt); - Log(LogLevel::Error, category, fmt, args); - va_end(args); - } -} // namespace Juliet +void LogError(LogCategory category, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + Log(LogLevel::Error, category, fmt, args); + va_end(args); +} diff --git a/Juliet/src/Core/Math/MathRound.cpp b/Juliet/src/Core/Math/MathRound.cpp index 7c1984a..8f24190 100644 --- a/Juliet/src/Core/Math/MathRound.cpp +++ b/Juliet/src/Core/Math/MathRound.cpp @@ -1,70 +1,67 @@ -#include +#include #include -namespace Juliet +// From MUSL lib https://github.com/rofl0r/musl +namespace { - // From MUSL lib https://github.com/rofl0r/musl - namespace + consteval float GetEps() { - consteval float GetEps() - { #if defined(__FLT_EVAL_METHOD__) - if constexpr (__FLT_EVAL_METHOD__ == 1) - { - return static_cast(DBL_EPSILON); - } - if constexpr (__FLT_EVAL_METHOD__ == 2) - { - return static_cast(LDBL_EPSILON); - } + if constexpr (__FLT_EVAL_METHOD__ == 1) + { + return static_cast(DBL_EPSILON); + } + if constexpr (__FLT_EVAL_METHOD__ == 2) + { + return static_cast(LDBL_EPSILON); + } #endif - return FLT_EPSILON; - } - - constexpr float EPS = GetEps(); - constexpr float toint = 1.0f / EPS; - } // namespace - - float RoundF(float value) - { - union - { - float f; - uint32 i; - } u = { value }; - auto e = u.i >> 23 & 0xff; - float y = 0.0f; - - if (e >= 0x7f + 23) - { - return value; - } - if (u.i >> 31) - { - value = -value; - } - if (e < 0x7f - 1) - { - ForceEval(value + toint); - return 0 * u.f; - } - y = value + toint - toint - value; - if (y > 0.5f) - { - y = y + value - 1; - } - else if (y <= -0.5f) - { - y = y + value + 1; - } - else - { - y = y + value; - } - if (u.i >> 31) - { - y = -y; - } - return y; + return FLT_EPSILON; } -} // namespace Juliet + + constexpr float EPS = GetEps(); + constexpr float toint = 1.0f / EPS; +} // namespace + +float RoundF(float value) +{ + union + { + float f; + uint32 i; + } u = { value }; + auto e = u.i >> 23 & 0xff; + float y = 0.0f; + + if (e >= 0x7f + 23) + { + return value; + } + if (u.i >> 31) + { + value = -value; + } + if (e < 0x7f - 1) + { + ForceEval(value + toint); + return 0 * u.f; + } + y = value + toint - toint - value; + if (y > 0.5f) + { + y = y + value - 1; + } + else if (y <= -0.5f) + { + y = y + value + 1; + } + else + { + y = y + value; + } + if (u.i >> 31) + { + y = -y; + } + return y; +} diff --git a/Juliet/src/Core/Math/Math_Private.h b/Juliet/src/Core/Math/Math_Private.h index 19106c3..d51b88c 100644 --- a/Juliet/src/Core/Math/Math_Private.h +++ b/Juliet/src/Core/Math/Math_Private.h @@ -1,53 +1,50 @@ -#pragma once +#pragma once -namespace Juliet -{ // From MUSL lib https://github.com/rofl0r/musl #ifndef fp_force_evalf #define fp_force_evalf fp_force_evalf - static inline void fp_force_evalf(float x) - { - volatile float y; - y = x; - (void)y; - } +static inline void fp_force_evalf(float x) +{ + volatile float y; + y = x; + (void)y; +} #endif #ifndef fp_force_eval #define fp_force_eval fp_force_eval - static inline void fp_force_eval(double x) - { - volatile double y; - y = x; - (void)y; - } +static inline void fp_force_eval(double x) +{ + volatile double y; + y = x; + (void)y; +} #endif #ifndef fp_force_evall #define fp_force_evall fp_force_evall - static inline void fp_force_evall(long double x) - { - volatile long double y; - y = x; - (void)y; - } +static inline void fp_force_evall(long double x) +{ + volatile long double y; + y = x; + (void)y; +} #endif - template - inline void ForceEval(T x) +template +inline void ForceEval(T x) +{ + if constexpr (std::is_same_v) { - if constexpr (std::is_same_v) - { - fp_force_evalf(x); - } - else if constexpr (std::is_same_v) - { - fp_force_eval(x); - } - else - { - fp_force_evall(x); - } + fp_force_evalf(x); } + else if constexpr (std::is_same_v) + { + fp_force_eval(x); + } + else + { + fp_force_evall(x); + } +} -} // namespace Juliet diff --git a/Juliet/src/Core/Memory/Allocator.cpp b/Juliet/src/Core/Memory/Allocator.cpp index 5d6ecb1..d7ff5c1 100644 --- a/Juliet/src/Core/Memory/Allocator.cpp +++ b/Juliet/src/Core/Memory/Allocator.cpp @@ -1,48 +1,45 @@ -#include +#include -namespace Juliet +// Uninitialized allocation +void* Malloc(size_t total_size) { - // Uninitialized allocation - void* Malloc(size_t total_size) + // Cant allocate 0 + if (!total_size) { - // Cant allocate 0 - if (!total_size) - { - total_size = 1; - } - - void* retMemory = malloc(total_size); - Assert(retMemory && "Out of memory"); - - return retMemory; + total_size = 1; } - // Initialized to 0 allocation - void* Calloc(size_t nb_elem, size_t elem_size) + void* retMemory = malloc(total_size); + Assert(retMemory && "Out of memory"); + + return retMemory; +} + +// Initialized to 0 allocation +void* Calloc(size_t nb_elem, size_t elem_size) +{ + // cant allocate 0 + if (!nb_elem || !elem_size) { - // cant allocate 0 - if (!nb_elem || !elem_size) - { - nb_elem = 1; - elem_size = 1; - } - - void* retMemory = calloc(nb_elem, elem_size); - Assert(retMemory && "Out of memory"); - - return retMemory; + nb_elem = 1; + elem_size = 1; } + + void* retMemory = calloc(nb_elem, elem_size); + Assert(retMemory && "Out of memory"); + + return retMemory; +} \ - void* Realloc(void* memory, size_t newSize) +void* Realloc(void* memory, size_t newSize) +{ + if (!newSize) { - if (!newSize) - { - newSize = 1; - } - - void* retMemory = realloc(memory, newSize); - Assert(retMemory && "Out of memory"); - - return retMemory; + newSize = 1; } -} // namespace Juliet + + void* retMemory = realloc(memory, newSize); + Assert(retMemory && "Out of memory"); + + return retMemory; +} diff --git a/Juliet/src/Core/Memory/MemoryArena.cpp b/Juliet/src/Core/Memory/MemoryArena.cpp index bc67799..a9abddf 100644 --- a/Juliet/src/Core/Memory/MemoryArena.cpp +++ b/Juliet/src/Core/Memory/MemoryArena.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -8,228 +8,225 @@ #include #include -namespace Juliet +// TODO Get page size from os kernel call (dwPageSize) +namespace { - // TODO Get page size from os kernel call (dwPageSize) - namespace - { - constexpr uint64 k_PageSize = Kilobytes(4); - } // namespace + constexpr uint64 k_PageSize = Kilobytes(4); +} // namespace - // https://github.com/EpicGamesExt/raddebugger/blob/master/src/base/base_arena.c +// https://github.com/EpicGamesExt/raddebugger/blob/master/src/base/base_arena.c - Arena* ArenaAllocate(const ArenaParams& params, const std::source_location& loc) - { - Log(LogLevel::Message, LogCategory::Core, "Allocating from %s : %ul", loc.file_name(), loc.line()); +Arena* ArenaAllocate(const ArenaParams& params, const std::source_location& loc) +{ + Log(LogLevel::Message, LogCategory::Core, "Allocating from %s : %ul", loc.file_name(), loc.line()); - uint64 reserve_size = AlignPow2(params.ReserveSize, k_PageSize); - uint64 commit_size = AlignPow2(params.CommitSize, k_PageSize); + uint64 reserve_size = AlignPow2(params.ReserveSize, k_PageSize); + uint64 commit_size = AlignPow2(params.CommitSize, k_PageSize); - // TODO: handle large pages - Byte* baseMem = Memory::OS_Reserve(reserve_size); - Memory::OS_Commit(baseMem, commit_size); + // TODO: handle large pages + Byte* baseMem = Memory::OS_Reserve(reserve_size); + Memory::OS_Commit(baseMem, commit_size); - Arena* arena = reinterpret_cast(baseMem); - arena->Current = arena; + Arena* arena = reinterpret_cast(baseMem); + arena->Current = arena; - arena->CommitSize = commit_size; - arena->ReserveSize = reserve_size; + arena->CommitSize = commit_size; + arena->ReserveSize = reserve_size; - arena->Committed = commit_size; - arena->Reserved = reserve_size; + arena->Committed = commit_size; + arena->Reserved = reserve_size; - arena->BasePosition = 0; - arena->Position = k_ArenaHeaderSize; + arena->BasePosition = 0; + arena->Position = k_ArenaHeaderSize; #if JULIET_DEBUG - arena->CanReserveMore = params.CanReserveMore; - arena->FirstDebugInfo = nullptr; + arena->CanReserveMore = params.CanReserveMore; + arena->FirstDebugInfo = nullptr; - if (params.Name == nullptr) - { - arena->Name = "NoName"; - } - else - { - arena->Name = params.Name; - } + if (params.Name == nullptr) + { + arena->Name = "NoName"; + } + else + { + arena->Name = params.Name; + } - DebugArenaSetDebugName(arena, arena->Name); - DebugRegisterArena(arena); + DebugArenaSetDebugName(arena, arena->Name); + DebugRegisterArena(arena); #endif - return arena; - } + return arena; +} - void ArenaRelease(NonNullPtr arena) +void ArenaRelease(NonNullPtr arena) +{ + // Release active blocks (Current chain) + for (Arena *node = arena->Current, *previous = nullptr; node != nullptr; node = previous) { - // Release active blocks (Current chain) - for (Arena *node = arena->Current, *previous = nullptr; node != nullptr; node = previous) - { - previous = node->Previous; + previous = node->Previous; - JULIET_DEBUG_ONLY(DebugUnregisterArena(node);) - JULIET_DEBUG_ONLY(DebugArenaFreeBlock(node);) + JULIET_DEBUG_ONLY(DebugUnregisterArena(node);) + JULIET_DEBUG_ONLY(DebugArenaFreeBlock(node);) - Memory::OS_Release(node, node->Reserved); - } + Memory::OS_Release(node, node->Reserved); } +} - void* ArenaPush(NonNullPtr arena, size_t size, size_t align, bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag)) +void* ArenaPush(NonNullPtr arena, size_t size, size_t align, bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag)) +{ + // Assert(IsPowerOfTwo(align)); + Arena* current = arena->Current; + size_t positionPrePush = AlignPow2(current->Position, align); + size_t positionPostPush = positionPrePush + size; + + // If allowed and needed, add a new block and chain it to the arena. + if (current->Reserved < positionPostPush /* flags : chaining allowed */) { - // Assert(IsPowerOfTwo(align)); - Arena* current = arena->Current; - size_t positionPrePush = AlignPow2(current->Position, align); - size_t positionPostPush = positionPrePush + size; + Assert(arena->CanReserveMore); - // If allowed and needed, add a new block and chain it to the arena. - if (current->Reserved < positionPostPush /* flags : chaining allowed */) + Arena* newBlock = nullptr; { - Assert(arena->CanReserveMore); - - Arena* newBlock = nullptr; + Arena* prev_block; + for (newBlock = arena->FreeBlockLast, prev_block = nullptr; newBlock != nullptr; + prev_block = newBlock, newBlock = newBlock->Previous) { - Arena* prev_block; - for (newBlock = arena->FreeBlockLast, prev_block = nullptr; newBlock != nullptr; - prev_block = newBlock, newBlock = newBlock->Previous) + if (newBlock->Reserved >= AlignPow2(newBlock->Position, align) + size) { - if (newBlock->Reserved >= AlignPow2(newBlock->Position, align) + size) + if (prev_block) { - if (prev_block) - { - prev_block->Previous = newBlock->Previous; - } - else - { - arena->FreeBlockLast = newBlock->Previous; - } - break; + prev_block->Previous = newBlock->Previous; } + else + { + arena->FreeBlockLast = newBlock->Previous; + } + break; } } + } - if (newBlock == nullptr) + if (newBlock == nullptr) + { + size_t reserveSize = current->ReserveSize; + size_t commitSize = current->CommitSize; + + if (size + k_ArenaHeaderSize > reserveSize) { - size_t reserveSize = current->ReserveSize; - size_t commitSize = current->CommitSize; - - if (size + k_ArenaHeaderSize > reserveSize) - { - reserveSize = AlignPow2(size + k_ArenaHeaderSize, align); - commitSize = AlignPow2(size + k_ArenaHeaderSize, align); - } - - newBlock = ArenaAllocate({ .ReserveSize = reserveSize, .CommitSize = commitSize, .Name = arena->Name }); + reserveSize = AlignPow2(size + k_ArenaHeaderSize, align); + commitSize = AlignPow2(size + k_ArenaHeaderSize, align); } - newBlock->BasePosition = current->BasePosition + current->Reserved; - SingleLinkedListPushPrevious(arena->Current, newBlock); - - current = newBlock; - positionPrePush = AlignPow2(current->Position, align); - positionPostPush = positionPrePush + size; + newBlock = ArenaAllocate({ .ReserveSize = reserveSize, .CommitSize = commitSize, .Name = arena->Name }); } - size_t sizeToZero = 0; - if (shouldBeZeroed) - { - sizeToZero = Min(current->Committed, positionPostPush) - positionPrePush; - } + newBlock->BasePosition = current->BasePosition + current->Reserved; + SingleLinkedListPushPrevious(arena->Current, newBlock); - // If needed commit new pages - if (current->Committed < positionPostPush) - { - size_t commitPostAligned = positionPostPush + current->CommitSize - 1; - commitPostAligned -= commitPostAligned % current->CommitSize; - size_t commitPostClamped = ClampTop(commitPostAligned, current->Reserved); - size_t commitSize = commitPostClamped - current->Committed; - Byte* commitPtr = reinterpret_cast(current) + current->Committed; - - // TODO commit_large - Memory::OS_Commit(commitPtr, commitSize); - - current->Committed = commitPostClamped; - } - - // Push on the current block - void* result = nullptr; - if (current->Committed >= positionPostPush) - { - result = reinterpret_cast(current) + positionPrePush; - current->Position = positionPostPush; - - JULIET_DEBUG_ONLY( - if (!IsDebugInfoArena(arena)) { DebugArenaAddDebugInfo(current, size, positionPrePush, tag); }) - - if (sizeToZero != 0) - { - MemoryZero(result, sizeToZero); - } - } - - if (result == nullptr) [[unlikely]] - { - Log(LogLevel::Error, LogCategory::Core, "Fatal Allocation Failure - Unexpected allocation failure"); - Assert(false, "Fatal Allocation Failure - Unexpected allocation failure"); - } - - return result; + current = newBlock; + positionPrePush = AlignPow2(current->Position, align); + positionPostPush = positionPrePush + size; } - void ArenaPopTo(NonNullPtr arena, size_t position) + size_t sizeToZero = 0; + if (shouldBeZeroed) { - size_t clampedPosition = ClampBottom(k_ArenaHeaderSize, position); - Arena* current = arena->Current; + sizeToZero = Min(current->Committed, positionPostPush) - positionPrePush; + } - for (Arena* previous = nullptr; current->BasePosition >= clampedPosition; current = previous) + // If needed commit new pages + if (current->Committed < positionPostPush) + { + size_t commitPostAligned = positionPostPush + current->CommitSize - 1; + commitPostAligned -= commitPostAligned % current->CommitSize; + size_t commitPostClamped = ClampTop(commitPostAligned, current->Reserved); + size_t commitSize = commitPostClamped - current->Committed; + Byte* commitPtr = reinterpret_cast(current) + current->Committed; + + // TODO commit_large + Memory::OS_Commit(commitPtr, commitSize); + + current->Committed = commitPostClamped; + } + + // Push on the current block + void* result = nullptr; + if (current->Committed >= positionPostPush) + { + result = reinterpret_cast(current) + positionPrePush; + current->Position = positionPostPush; + + JULIET_DEBUG_ONLY( + if (!IsDebugInfoArena(arena)) { DebugArenaAddDebugInfo(current, size, positionPrePush, tag); }) + + if (sizeToZero != 0) { - previous = current->Previous; - current->Position = k_ArenaHeaderSize; - - JULIET_DEBUG_ONLY(DebugArenaFreeBlock(current);) - - SingleLinkedListPushPrevious(arena->FreeBlockLast, current); + MemoryZero(result, sizeToZero); } - - arena->Current = current; - size_t newPosition = clampedPosition - current->BasePosition; - Assert(newPosition <= current->Position); - current->Position = newPosition; - - JULIET_DEBUG_ONLY(DebugArenaPopTo(current, newPosition);) } - void ArenaPop(NonNullPtr arena, size_t amount) + if (result == nullptr) [[unlikely]] { - size_t oldPosition = ArenaPos(arena); - size_t newPosition = oldPosition; - if (amount < oldPosition) - { - newPosition = oldPosition - amount; - } - ArenaPopTo(arena, newPosition); + Log(LogLevel::Error, LogCategory::Core, "Fatal Allocation Failure - Unexpected allocation failure"); + Assert(false, "Fatal Allocation Failure - Unexpected allocation failure"); } - void ArenaClear(NonNullPtr arena) + return result; +} + +void ArenaPopTo(NonNullPtr arena, size_t position) +{ + size_t clampedPosition = ClampBottom(k_ArenaHeaderSize, position); + Arena* current = arena->Current; + + for (Arena* previous = nullptr; current->BasePosition >= clampedPosition; current = previous) { - ArenaPopTo(arena, 0); + previous = current->Previous; + current->Position = k_ArenaHeaderSize; + + JULIET_DEBUG_ONLY(DebugArenaFreeBlock(current);) + + SingleLinkedListPushPrevious(arena->FreeBlockLast, current); } - size_t ArenaPos(NonNullPtr arena) - { - Arena* current = arena->Current; - size_t position = current->BasePosition + current->Position; - return position; - } + arena->Current = current; + size_t newPosition = clampedPosition - current->BasePosition; + Assert(newPosition <= current->Position); + current->Position = newPosition; - TempArena ArenaTempBegin(NonNullPtr arena) - { - index_t position = ArenaPos(arena); - return { arena.Get(), position }; - } + JULIET_DEBUG_ONLY(DebugArenaPopTo(current, newPosition);) +} - void ArenaTempEnd(TempArena temp) +void ArenaPop(NonNullPtr arena, size_t amount) +{ + size_t oldPosition = ArenaPos(arena); + size_t newPosition = oldPosition; + if (amount < oldPosition) { - ArenaPopTo(temp.Arena, temp.Position); + newPosition = oldPosition - amount; } -} // namespace Juliet + ArenaPopTo(arena, newPosition); +} + +void ArenaClear(NonNullPtr arena) +{ + ArenaPopTo(arena, 0); +} + +size_t ArenaPos(NonNullPtr arena) +{ + Arena* current = arena->Current; + size_t position = current->BasePosition + current->Position; + return position; +} + +TempArena ArenaTempBegin(NonNullPtr arena) +{ + index_t position = ArenaPos(arena); + return { arena.Get(), position }; +} + +void ArenaTempEnd(TempArena temp) +{ + ArenaPopTo(temp.Arena, temp.Position); +} diff --git a/Juliet/src/Core/Memory/MemoryArenaDebug.cpp b/Juliet/src/Core/Memory/MemoryArenaDebug.cpp index fe9c09c..2e1c228 100644 --- a/Juliet/src/Core/Memory/MemoryArenaDebug.cpp +++ b/Juliet/src/Core/Memory/MemoryArenaDebug.cpp @@ -1,173 +1,170 @@ -#include // For Arena definition +#include // For Arena definition #include #if JULIET_DEBUG -namespace Juliet +Arena* g_ArenaGlobalHead = nullptr; +Arena* g_DebugInfoArena = nullptr; +ArenaDebugInfo* g_DebugInfoFreeList = nullptr; +ArenaAllocation* g_ArenaAllocationFreeList = nullptr; + +// --- Internal Helpers --- +static ArenaDebugInfo* AllocDebugInfo() { - Arena* g_ArenaGlobalHead = nullptr; - Arena* g_DebugInfoArena = nullptr; - ArenaDebugInfo* g_DebugInfoFreeList = nullptr; - ArenaAllocation* g_ArenaAllocationFreeList = nullptr; - - // --- Internal Helpers --- - static ArenaDebugInfo* AllocDebugInfo() + if (g_DebugInfoFreeList) { - if (g_DebugInfoFreeList) - { - ArenaDebugInfo* info = g_DebugInfoFreeList; - g_DebugInfoFreeList = info->Next; - info->Next = nullptr; - return info; - } - - if (!g_DebugInfoArena) - { - // Create a dedicated arena for debug info - g_DebugInfoArena = - ArenaAllocate({ .ReserveSize = Megabytes(16), .CommitSize = Kilobytes(64), .Name = "Debug Info Arena" }); - } - - return ArenaPushStruct(g_DebugInfoArena JULIET_DEBUG_PARAM("ArenaDebugInfo")); + ArenaDebugInfo* info = g_DebugInfoFreeList; + g_DebugInfoFreeList = info->Next; + info->Next = nullptr; + return info; } - Arena* GetDebugInfoArena() + if (!g_DebugInfoArena) { - if (!g_DebugInfoArena) - { - g_DebugInfoArena = - ArenaAllocate({ .ReserveSize = Megabytes(16), .CommitSize = Kilobytes(64), .Name = "Debug Info Arena" }); - } - return g_DebugInfoArena; - } - static void FreeDebugInfo(ArenaDebugInfo* info) - { - if (info) - { - info->Next = g_DebugInfoFreeList; - g_DebugInfoFreeList = info; - } + // Create a dedicated arena for debug info + g_DebugInfoArena = + ArenaAllocate({ .ReserveSize = Megabytes(16), .CommitSize = Kilobytes(64), .Name = "Debug Info Arena" }); } - void DebugRegisterArena(NonNullPtr arena) - { - // Add to Global List - // Note: Not thread safe, assuming single thread for now as per context - if (g_ArenaGlobalHead) - { - g_ArenaGlobalHead->GlobalPrev = arena; - } - arena->GlobalNext = g_ArenaGlobalHead; - arena->GlobalPrev = nullptr; - g_ArenaGlobalHead = arena; - } + return ArenaPushStruct(g_DebugInfoArena JULIET_DEBUG_PARAM("ArenaDebugInfo")); +} - void DebugUnregisterArena(NonNullPtr arena) +Arena* GetDebugInfoArena() +{ + if (!g_DebugInfoArena) { - // Remove from Global List - if (arena->GlobalPrev) + g_DebugInfoArena = + ArenaAllocate({ .ReserveSize = Megabytes(16), .CommitSize = Kilobytes(64), .Name = "Debug Info Arena" }); + } + return g_DebugInfoArena; +} +static void FreeDebugInfo(ArenaDebugInfo* info) +{ + if (info) + { + info->Next = g_DebugInfoFreeList; + g_DebugInfoFreeList = info; + } +} + +void DebugRegisterArena(NonNullPtr arena) +{ + // Add to Global List + // Note: Not thread safe, assuming single thread for now as per context + if (g_ArenaGlobalHead) + { + g_ArenaGlobalHead->GlobalPrev = arena; + } + arena->GlobalNext = g_ArenaGlobalHead; + arena->GlobalPrev = nullptr; + g_ArenaGlobalHead = arena; +} + +void DebugUnregisterArena(NonNullPtr arena) +{ + // Remove from Global List + if (arena->GlobalPrev) + { + arena->GlobalPrev->GlobalNext = arena->GlobalNext; + } + else + { + g_ArenaGlobalHead = arena->GlobalNext; + } + if (arena->GlobalNext) + { + arena->GlobalNext->GlobalPrev = arena->GlobalPrev; + } + arena->GlobalPrev = nullptr; + arena->GlobalNext = nullptr; +} + +void DebugArenaSetDebugName(NonNullPtr arena, const char* name) +{ + arena->Name = name; +} + +bool IsDebugInfoArena(const Arena* arena) +{ + return arena == g_DebugInfoArena; +} + +void DebugArenaFreeBlock(Arena* block) +{ + ArenaDebugInfo* info = block->FirstDebugInfo; + while (info) + { + ArenaDebugInfo* nextInfo = info->Next; + FreeDebugInfo(info); + info = nextInfo; + } + block->FirstDebugInfo = nullptr; +} + +void DebugArenaRemoveAllocation(Arena* block, size_t oldOffset) +{ + ArenaDebugInfo** prevInfo = &block->FirstDebugInfo; + ArenaDebugInfo* info = block->FirstDebugInfo; + + while (info) + { + if (info->Offset == oldOffset) // Found it { - arena->GlobalPrev->GlobalNext = arena->GlobalNext; + *prevInfo = info->Next; + FreeDebugInfo(info); + break; + } + prevInfo = &info->Next; + info = info->Next; + } +} + +void DebugArenaPopTo(Arena* block, size_t newPosition) +{ + ArenaDebugInfo** prevInfo = &block->FirstDebugInfo; + ArenaDebugInfo* info = block->FirstDebugInfo; + while (info) + { + if (info->Offset >= newPosition) + { + ArenaDebugInfo* toFree = info; + *prevInfo = info->Next; // Unlink + info = info->Next; // Advance + FreeDebugInfo(toFree); } else { - g_ArenaGlobalHead = arena->GlobalNext; - } - if (arena->GlobalNext) - { - arena->GlobalNext->GlobalPrev = arena->GlobalPrev; - } - arena->GlobalPrev = nullptr; - arena->GlobalNext = nullptr; - } - - void DebugArenaSetDebugName(NonNullPtr arena, const char* name) - { - arena->Name = name; - } - - bool IsDebugInfoArena(const Arena* arena) - { - return arena == g_DebugInfoArena; - } - - void DebugArenaFreeBlock(Arena* block) - { - ArenaDebugInfo* info = block->FirstDebugInfo; - while (info) - { - ArenaDebugInfo* nextInfo = info->Next; - FreeDebugInfo(info); - info = nextInfo; - } - block->FirstDebugInfo = nullptr; - } - - void DebugArenaRemoveAllocation(Arena* block, size_t oldOffset) - { - ArenaDebugInfo** prevInfo = &block->FirstDebugInfo; - ArenaDebugInfo* info = block->FirstDebugInfo; - - while (info) - { - if (info->Offset == oldOffset) // Found it - { - *prevInfo = info->Next; - FreeDebugInfo(info); - break; - } prevInfo = &info->Next; info = info->Next; } } +} - void DebugArenaPopTo(Arena* block, size_t newPosition) +void DebugArenaAddDebugInfo(Arena* block, size_t size, size_t offset, const char* tag) +{ + ArenaDebugInfo* info = AllocDebugInfo(); + if (info) { - ArenaDebugInfo** prevInfo = &block->FirstDebugInfo; - ArenaDebugInfo* info = block->FirstDebugInfo; - while (info) + if (tag) { - if (info->Offset >= newPosition) - { - ArenaDebugInfo* toFree = info; - *prevInfo = info->Next; // Unlink - info = info->Next; // Advance - FreeDebugInfo(toFree); - } - else - { - prevInfo = &info->Next; - info = info->Next; - } + String copiedTag = StringCopy(g_DebugInfoArena, WrapString(tag)); + info->Tag = copiedTag.Str; } - } - - void DebugArenaAddDebugInfo(Arena* block, size_t size, size_t offset, const char* tag) - { - ArenaDebugInfo* info = AllocDebugInfo(); - if (info) + else { - if (tag) - { - String copiedTag = StringCopy(g_DebugInfoArena, WrapString(tag)); - info->Tag = copiedTag.Str; - } - else - { - info->Tag = "Untagged"; - } - info->Size = size; - info->Offset = offset; - info->Next = block->FirstDebugInfo; - block->FirstDebugInfo = info; + info->Tag = "Untagged"; } + info->Size = size; + info->Offset = offset; + info->Next = block->FirstDebugInfo; + block->FirstDebugInfo = info; } +} - Arena* GetGlobalArenaListHead() - { - return g_ArenaGlobalHead; - } +Arena* GetGlobalArenaListHead() +{ + return g_ArenaGlobalHead; +} -} // namespace Juliet #endif diff --git a/Juliet/src/Core/Memory/MemoryArenaTests.cpp b/Juliet/src/Core/Memory/MemoryArenaTests.cpp index ded87f8..bb275d9 100644 --- a/Juliet/src/Core/Memory/MemoryArenaTests.cpp +++ b/Juliet/src/Core/Memory/MemoryArenaTests.cpp @@ -1,11 +1,11 @@ -#include +#include #include #include #include #if JULIET_DEBUG -namespace Juliet::UnitTest +namespace UnitTest { struct TestStruct { @@ -119,5 +119,5 @@ namespace Juliet::UnitTest printf("All Paged MemoryArena tests passed.\n"); } -} // namespace Juliet::UnitTest +} // namespace UnitTest #endif diff --git a/Juliet/src/Core/Memory/ScratchArena.cpp b/Juliet/src/Core/Memory/ScratchArena.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/Juliet/src/Core/Networking/NetworkPacket.cpp b/Juliet/src/Core/Networking/NetworkPacket.cpp index f6ccae1..5db4ffd 100644 --- a/Juliet/src/Core/Networking/NetworkPacket.cpp +++ b/Juliet/src/Core/Networking/NetworkPacket.cpp @@ -1,68 +1,65 @@ -#include +#include #include #include #define TO_BUFFER(ptr) reinterpret_cast(ptr) -namespace Juliet +NetworkPacket::NetworkPacket() = default; +NetworkPacket::NetworkPacket(Arena& arena) { - NetworkPacket::NetworkPacket() = default; - NetworkPacket::NetworkPacket(Arena& arena) + Data.Create(&arena); +} +NetworkPacket::~NetworkPacket() = default; +NetworkPacket::NetworkPacket(NetworkPacket&) = default; +NetworkPacket& NetworkPacket::operator=(const NetworkPacket&) = default; +NetworkPacket::NetworkPacket(NetworkPacket&&) noexcept = default; +NetworkPacket& NetworkPacket::operator=(NetworkPacket&&) noexcept = default; + +void NetworkPacket::Create(Arena& arena) +{ + Data.Create(&arena); +} + +ByteBuffer NetworkPacket::GetRawData() +{ + ByteBuffer buffer{}; + buffer.Data = Data.DataPtr(); + buffer.Size = Data.Size(); + + return buffer; +} + +// Begin - Unpack + +// End - Unpack +// Begin - Pack +NetworkPacket& NetworkPacket::operator<<(uint32 value) +{ + uint32 toWrite = htonl(value); + Append({ TO_BUFFER(&toWrite), sizeof(toWrite) }); + return *this; +} + +NetworkPacket& NetworkPacket::operator<<(char* data) +{ + Assert(data && "NetworkPacket::operator<< Data must not be null"); + + // First insert string length in network byte order + const uint32 length = static_cast(std::strlen(data)); + *this << length; + + // Then insert the chars + Append({ TO_BUFFER(data), length * sizeof(char) }); + + return *this; +} +// End - Pack + +void NetworkPacket::Append(ByteBuffer buffer) +{ + if (buffer.Data && (buffer.Size > 0)) { - Data.Create(&arena); + Data.PushBack(TO_BUFFER(buffer.Data), buffer.Size); } - NetworkPacket::~NetworkPacket() = default; - NetworkPacket::NetworkPacket(NetworkPacket&) = default; - NetworkPacket& NetworkPacket::operator=(const NetworkPacket&) = default; - NetworkPacket::NetworkPacket(NetworkPacket&&) noexcept = default; - NetworkPacket& NetworkPacket::operator=(NetworkPacket&&) noexcept = default; +} - void NetworkPacket::Create(Arena& arena) - { - Data.Create(&arena); - } - - ByteBuffer NetworkPacket::GetRawData() - { - ByteBuffer buffer{}; - buffer.Data = Data.DataPtr(); - buffer.Size = Data.Size(); - - return buffer; - } - - // Begin - Unpack - - // End - Unpack - // Begin - Pack - NetworkPacket& NetworkPacket::operator<<(uint32 value) - { - uint32 toWrite = htonl(value); - Append({ TO_BUFFER(&toWrite), sizeof(toWrite) }); - return *this; - } - - NetworkPacket& NetworkPacket::operator<<(char* data) - { - Assert(data && "NetworkPacket::operator<< Data must not be null"); - - // First insert string length in network byte order - const uint32 length = static_cast(std::strlen(data)); - *this << length; - - // Then insert the chars - Append({ TO_BUFFER(data), length * sizeof(char) }); - - return *this; - } - // End - Pack - - void NetworkPacket::Append(ByteBuffer buffer) - { - if (buffer.Data && (buffer.Size > 0)) - { - Data.PushBack(TO_BUFFER(buffer.Data), buffer.Size); - } - } - -} // namespace Juliet diff --git a/Juliet/src/Core/Networking/Socket.cpp b/Juliet/src/Core/Networking/Socket.cpp index c79011b..9e6d070 100644 --- a/Juliet/src/Core/Networking/Socket.cpp +++ b/Juliet/src/Core/Networking/Socket.cpp @@ -1,85 +1,82 @@ -#include +#include #include #include #include #include -namespace Juliet +Socket::Socket(Protocol protocol) + : Handle(SocketImpl::GetInvalidSocketHandle()) + , ProtocolType(protocol) { - Socket::Socket(Protocol protocol) - : Handle(SocketImpl::GetInvalidSocketHandle()) - , ProtocolType(protocol) +} + +Socket::~Socket() +{ + Close(); +} + +Socket::Socket(Socket&& /*other*/) noexcept +{ + Unimplemented(); +} + +Socket& Socket::operator=(Socket&& /*socket*/) noexcept +{ + Unimplemented(); + return *this; +} + +bool Socket::IsValid() const +{ + return Handle != SocketImpl::GetInvalidSocketHandle(); +} + +void Socket::Create() +{ + if (Handle != SocketImpl::GetInvalidSocketHandle()) { + Log(LogLevel::Message, LogCategory::Networking, "Socket already created"); + return; } - Socket::~Socket() + const SocketHandle handle = socket(PF_INET, ProtocolType == Protocol::TCP ? SOCK_STREAM : SOCK_DGRAM, 0); + if (handle == SocketImpl::GetInvalidSocketHandle()) { - Close(); + Log(LogLevel::Error, LogCategory::Networking, "Failed to create socket. Error [%s]", SocketImpl::GetErrorString()); + return; } - Socket::Socket(Socket&& /*other*/) noexcept + CreateFromHandle(handle); +} +void Socket::CreateFromHandle(SocketHandle handle) +{ + if (Handle != SocketImpl::GetInvalidSocketHandle()) { - Unimplemented(); + Log(LogLevel::Message, LogCategory::Networking, "Socket already created"); + return; } - Socket& Socket::operator=(Socket&& /*socket*/) noexcept - { - Unimplemented(); - return *this; - } + Handle = handle; - bool Socket::IsValid() const + if (ProtocolType == Protocol::TCP) { - return Handle != SocketImpl::GetInvalidSocketHandle(); - } - - void Socket::Create() - { - if (Handle != SocketImpl::GetInvalidSocketHandle()) + int yes = 1; + if (setsockopt(Handle, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&yes), sizeof(yes)) == -1) { - Log(LogLevel::Message, LogCategory::Networking, "Socket already created"); - return; - } - - const SocketHandle handle = socket(PF_INET, ProtocolType == Protocol::TCP ? SOCK_STREAM : SOCK_DGRAM, 0); - if (handle == SocketImpl::GetInvalidSocketHandle()) - { - Log(LogLevel::Error, LogCategory::Networking, "Failed to create socket. Error [%s]", SocketImpl::GetErrorString()); - return; - } - - CreateFromHandle(handle); - } - void Socket::CreateFromHandle(SocketHandle handle) - { - if (Handle != SocketImpl::GetInvalidSocketHandle()) - { - Log(LogLevel::Message, LogCategory::Networking, "Socket already created"); - return; - } - - Handle = handle; - - if (ProtocolType == Protocol::TCP) - { - int yes = 1; - if (setsockopt(Handle, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&yes), sizeof(yes)) == -1) - { - Log(LogLevel::Error, LogCategory::Networking, "Cant set TCP_NODELAY."); - } - } - else - { - Assert(false); // Unimplemented + Log(LogLevel::Error, LogCategory::Networking, "Cant set TCP_NODELAY."); } } - - void Socket::Close() + else { - if (Handle != SocketImpl::GetInvalidSocketHandle()) - { - SocketImpl::Close(Handle); - Handle = SocketImpl::GetInvalidSocketHandle(); - } + Assert(false); // Unimplemented } -} // namespace Juliet +} + +void Socket::Close() +{ + if (Handle != SocketImpl::GetInvalidSocketHandle()) + { + SocketImpl::Close(Handle); + Handle = SocketImpl::GetInvalidSocketHandle(); + } +} diff --git a/Juliet/src/Core/Networking/SocketPlatformImpl.h b/Juliet/src/Core/Networking/SocketPlatformImpl.h index 559c041..3780176 100644 --- a/Juliet/src/Core/Networking/SocketPlatformImpl.h +++ b/Juliet/src/Core/Networking/SocketPlatformImpl.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include @@ -11,7 +11,7 @@ // UNIMPLEMENT_SOCKETS #endif -namespace Juliet::SocketImpl +namespace SocketImpl { using MessageLenghtType = int; @@ -20,4 +20,4 @@ namespace Juliet::SocketImpl void Close(SOCKET socketHandle); const char* GetErrorString(); Socket::Status GetErrorStatus(); -} // namespace Juliet::SocketImpl +} // namespace SocketImpl diff --git a/Juliet/src/Core/Networking/TcpListener.cpp b/Juliet/src/Core/Networking/TcpListener.cpp index b2384d1..c0c0f6c 100644 --- a/Juliet/src/Core/Networking/TcpListener.cpp +++ b/Juliet/src/Core/Networking/TcpListener.cpp @@ -1,69 +1,66 @@ -#include +#include #include #include #include -namespace Juliet +TcpListener::TcpListener() + : Socket(Protocol::TCP) { - TcpListener::TcpListener() - : Socket(Protocol::TCP) +} + +Socket::Status TcpListener::Listen(uint16 port, uint32 address) +{ + // Unbind the internal socket. + // Allow reusing the same listener but switch port and addres + Close(); + + Create(); + + // Cant listen on broadcast + if (address == kBroadcastIp) { + return Status::Error; } - Socket::Status TcpListener::Listen(uint16 port, uint32 address) + sockaddr_in socketAddr = SocketImpl::CreateAddress(address, port); + if (bind(GetHandle(), reinterpret_cast(&socketAddr), sizeof(socketAddr)) == -1) { - // Unbind the internal socket. - // Allow reusing the same listener but switch port and addres - Close(); - - Create(); - - // Cant listen on broadcast - if (address == kBroadcastIp) - { - return Status::Error; - } - - sockaddr_in socketAddr = SocketImpl::CreateAddress(address, port); - if (bind(GetHandle(), reinterpret_cast(&socketAddr), sizeof(socketAddr)) == -1) - { - Log(LogLevel::Error, LogCategory::Networking, "Failed to bind TcpListener to port %d", port); - return Status::Error; - } - - if (listen(GetHandle(), SOMAXCONN) == -1) - { - Log(LogLevel::Error, LogCategory::Networking, "Failed to listen TcpListener to port %d", port); - return Status::Error; - } - - return Status::Ready; + Log(LogLevel::Error, LogCategory::Networking, "Failed to bind TcpListener to port %d", port); + return Status::Error; } - Socket::Status TcpListener::Accept(TcpSocket& socket) + if (listen(GetHandle(), SOMAXCONN) == -1) { - if (!IsValid()) - { - Log(LogLevel::Error, LogCategory::Networking, "Cannot accept connection because the socket is not listening"); - return Status::Error; - } - - SocketHandle client = ::accept(GetHandle(), nullptr, nullptr); - if (client == SocketImpl::GetInvalidSocketHandle()) - { - Log(LogLevel::Error, LogCategory::Networking, "Failed to accept a new connection. Error [%s]", - SocketImpl::GetErrorString()); - return Status::Error; - } - - socket.Close(); - socket.CreateFromHandle(client); - - return Status::Ready; + Log(LogLevel::Error, LogCategory::Networking, "Failed to listen TcpListener to port %d", port); + return Status::Error; } - void TcpListener::Close() + return Status::Ready; +} + +Socket::Status TcpListener::Accept(TcpSocket& socket) +{ + if (!IsValid()) { - Socket::Close(); + Log(LogLevel::Error, LogCategory::Networking, "Cannot accept connection because the socket is not listening"); + return Status::Error; } -} // namespace Juliet + + SocketHandle client = ::accept(GetHandle(), nullptr, nullptr); + if (client == SocketImpl::GetInvalidSocketHandle()) + { + Log(LogLevel::Error, LogCategory::Networking, "Failed to accept a new connection. Error [%s]", + SocketImpl::GetErrorString()); + return Status::Error; + } + + socket.Close(); + socket.CreateFromHandle(client); + + return Status::Ready; +} + +void TcpListener::Close() +{ + Socket::Close(); +} diff --git a/Juliet/src/Core/Networking/TcpSocket.cpp b/Juliet/src/Core/Networking/TcpSocket.cpp index c543afa..418c32d 100644 --- a/Juliet/src/Core/Networking/TcpSocket.cpp +++ b/Juliet/src/Core/Networking/TcpSocket.cpp @@ -1,96 +1,93 @@ -#include +#include #include #include #include #include -namespace Juliet +TcpSocket::TcpSocket() + : Socket(Protocol::TCP) { - TcpSocket::TcpSocket() - : Socket(Protocol::TCP) +} + +Socket::RequestStatus TcpSocket::Send(NetworkPacket& packet) +{ + ByteBuffer buffer = packet.GetRawData(); + + if (buffer.Size == 0 || buffer.Data == nullptr) { + Log(LogLevel::Error, LogCategory::Networking, "No data inside the network packet."); + return { Status::Error }; } - Socket::RequestStatus TcpSocket::Send(NetworkPacket& packet) + // Tcp socket opens a stream of data. + // Send function do not guarantee how the data will be sent and received. + // The receiver has no way to know the message stream has ended + // Because of that we will send the size of the packet first before sending the data. + + // TODO Use scratch allocator. + /* + Vector scratchVector; + scratchVector.resize(buffer.Size + sizeof(uint32)); + + // htonl converts uint32 from host byte order to network byte order + uint32 nlSize = htonl(static_cast(buffer.Size)); + + memcpy(scratchVector.data(), &nlSize, sizeof(nlSize)); + memcpy(scratchVector.data() + sizeof(nlSize), buffer.Data, buffer.Size); + + // TODO : Save within the packet the total size + make the ByteBuffer use the PartialSendIndex variable directly + // instead of memcopying the whole packet and ignoring part of it + ByteBuffer packetToSend{ .Data = scratchVector.data() + packet.PartialSendIndex, + .Size = scratchVector.size() - packet.PartialSendIndex }; + auto messageStatus = Send(packetToSend); + + if (messageStatus.Status == Status::Partial) { - ByteBuffer buffer = packet.GetRawData(); - - if (buffer.Size == 0 || buffer.Data == nullptr) - { - Log(LogLevel::Error, LogCategory::Networking, "No data inside the network packet."); - return { Status::Error }; - } - - // Tcp socket opens a stream of data. - // Send function do not guarantee how the data will be sent and received. - // The receiver has no way to know the message stream has ended - // Because of that we will send the size of the packet first before sending the data. - - // TODO Use scratch allocator. - /* - Vector scratchVector; - scratchVector.resize(buffer.Size + sizeof(uint32)); - - // htonl converts uint32 from host byte order to network byte order - uint32 nlSize = htonl(static_cast(buffer.Size)); - - memcpy(scratchVector.data(), &nlSize, sizeof(nlSize)); - memcpy(scratchVector.data() + sizeof(nlSize), buffer.Data, buffer.Size); - - // TODO : Save within the packet the total size + make the ByteBuffer use the PartialSendIndex variable directly - // instead of memcopying the whole packet and ignoring part of it - ByteBuffer packetToSend{ .Data = scratchVector.data() + packet.PartialSendIndex, - .Size = scratchVector.size() - packet.PartialSendIndex }; - auto messageStatus = Send(packetToSend); - - if (messageStatus.Status == Status::Partial) - { - packet.PartialSendIndex += messageStatus.Length; - } - else if (messageStatus.Status == Status::Done) - { - packet.PartialSendIndex = 0; - } - - return messageStatus; - */ - return {}; + packet.PartialSendIndex += messageStatus.Length; + } + else if (messageStatus.Status == Status::Done) + { + packet.PartialSendIndex = 0; } - Socket::RequestStatus TcpSocket::Send(ByteBuffer buffer) + return messageStatus; + */ + return {}; +} + +Socket::RequestStatus TcpSocket::Send(ByteBuffer buffer) +{ + RequestStatus request = {}; + + constexpr int sendFlags = 0; + int result = 0; + for (request.Length = 0; request.Length < buffer.Size; request.Length += static_cast(result)) { - RequestStatus request = {}; + result = ::send(GetHandle(), reinterpret_cast(buffer.Data + request.Length), + static_cast(buffer.Size) - + static_cast(request.Length), + sendFlags); - constexpr int sendFlags = 0; - int result = 0; - for (request.Length = 0; request.Length < buffer.Size; request.Length += static_cast(result)) + // Results is -1 when an error occured. + // https://pubs.opengroup.org/onlinepubs/000095399/functions/send.html + if (result < 0) { - result = ::send(GetHandle(), reinterpret_cast(buffer.Data + request.Length), - static_cast(buffer.Size) - - static_cast(request.Length), - sendFlags); + request.Status = SocketImpl::GetErrorStatus(); - // Results is -1 when an error occured. - // https://pubs.opengroup.org/onlinepubs/000095399/functions/send.html - if (result < 0) + if ((request.Status == Status::NotReady) && (request.Length > 0)) { - request.Status = SocketImpl::GetErrorStatus(); - - if ((request.Status == Status::NotReady) && (request.Length > 0)) - { - request.Status = Status::Partial; - } - - break; + request.Status = Status::Partial; } + + break; } - - return request; } - Socket::Status TcpSocket::Receive(NetworkPacket& /*outPacket*/) - { - return Status::Done; - } + return request; +} + +Socket::Status TcpSocket::Receive(NetworkPacket& /*outPacket*/) +{ + return Status::Done; +} -} // namespace Juliet diff --git a/Juliet/src/Core/Networking/Win32/Win32SocketPlatformImpl.cpp b/Juliet/src/Core/Networking/Win32/Win32SocketPlatformImpl.cpp index 494ee13..2274993 100644 --- a/Juliet/src/Core/Networking/Win32/Win32SocketPlatformImpl.cpp +++ b/Juliet/src/Core/Networking/Win32/Win32SocketPlatformImpl.cpp @@ -1,10 +1,10 @@ -#include +#include #include #include #include #include -namespace Juliet::SocketImpl +namespace SocketImpl { sockaddr_in CreateAddress(uint32 address, uint16 port) { @@ -58,26 +58,23 @@ namespace Juliet::SocketImpl } } -} // namespace Juliet::SocketImpl +} // namespace SocketImpl -namespace Juliet +// Windows needs its socket dll to be initialized for the whole process +struct WSAAutoRelease { - // Windows needs its socket dll to be initialized for the whole process - struct WSAAutoRelease + WSAAutoRelease() { - WSAAutoRelease() + WORD wVersionRequested = MAKEWORD(2, 2); + WSADATA wsaData; + if (WSAStartup(wVersionRequested, &wsaData) != 0) { - WORD wVersionRequested = MAKEWORD(2, 2); - WSADATA wsaData; - if (WSAStartup(wVersionRequested, &wsaData) != 0) - { - Log(LogLevel::Error, LogCategory::Core, "Failed to startup WinSock2"); - return; - } + Log(LogLevel::Error, LogCategory::Core, "Failed to startup WinSock2"); + return; } + } - ~WSAAutoRelease() { WSACleanup(); } - }; + ~WSAAutoRelease() { WSACleanup(); } +}; - WSAAutoRelease gWSAautoRelease; -} // namespace Juliet +WSAAutoRelease gWSAautoRelease; diff --git a/Juliet/src/Core/PCH.cpp b/Juliet/src/Core/PCH.cpp index 799cec2..4140e3d 100644 --- a/Juliet/src/Core/PCH.cpp +++ b/Juliet/src/Core/PCH.cpp @@ -1 +1 @@ -#include "Core/PCH.h" +#include "Core/PCH.h" diff --git a/Juliet/src/Core/Thread/ThreadContext.cpp b/Juliet/src/Core/Thread/ThreadContext.cpp index 7c1666b..18f4514 100644 --- a/Juliet/src/Core/Thread/ThreadContext.cpp +++ b/Juliet/src/Core/Thread/ThreadContext.cpp @@ -1,76 +1,73 @@ -#include +#include #include -namespace Juliet +thread_local thread_context* local_thread_context; + +thread_context* thread_context_alloc() { - thread_local thread_context* local_thread_context; + thread_local char name[2][1024]; + juliet_snprintf(name[0], sizeof(name[0]), "Scratch/0[TID:%u]", thread_id()); + juliet_snprintf(name[1], sizeof(name[1]), "Scratch/1[TID:%u]", thread_id()); + Arena* arena_0 = ArenaAllocate({ .Name = name[0] }); + Arena* arena_1 = ArenaAllocate({ .Name = name[1] }); - thread_context* thread_context_alloc() + thread_context* ctx = ArenaPushStruct(arena_0); + ctx->ScratchArenas[0] = arena_0; + ctx->ScratchArenas[1] = arena_1; + return ctx; +} + +void thread_context_release(NonNullPtr ctx) +{ + ArenaRelease(ctx->ScratchArenas[1]); + ArenaRelease(ctx->ScratchArenas[0]); +} + +void thread_context_select(NonNullPtr ctx) +{ + local_thread_context = ctx.Get(); +} + +thread_context* thread_context_current() +{ + Assert(local_thread_context); + return local_thread_context; +} + +Arena* thread_context_get_scratch(Arena** conflicts, size_t count) +{ + thread_context* ctx = thread_context_current(); + Arena* result = nullptr; + Arena** arena_ptr = ctx->ScratchArenas; + for (size_t i = 0; i < ArraySize(ctx->ScratchArenas); i += 1, arena_ptr += 1) { - thread_local char name[2][1024]; - juliet_snprintf(name[0], sizeof(name[0]), "Scratch/0[TID:%u]", thread_id()); - juliet_snprintf(name[1], sizeof(name[1]), "Scratch/1[TID:%u]", thread_id()); - Arena* arena_0 = ArenaAllocate({ .Name = name[0] }); - Arena* arena_1 = ArenaAllocate({ .Name = name[1] }); - - thread_context* ctx = ArenaPushStruct(arena_0); - ctx->ScratchArenas[0] = arena_0; - ctx->ScratchArenas[1] = arena_1; - return ctx; - } - - void thread_context_release(NonNullPtr ctx) - { - ArenaRelease(ctx->ScratchArenas[1]); - ArenaRelease(ctx->ScratchArenas[0]); - } - - void thread_context_select(NonNullPtr ctx) - { - local_thread_context = ctx.Get(); - } - - thread_context* thread_context_current() - { - Assert(local_thread_context); - return local_thread_context; - } - - Arena* thread_context_get_scratch(Arena** conflicts, size_t count) - { - thread_context* ctx = thread_context_current(); - Arena* result = nullptr; - Arena** arena_ptr = ctx->ScratchArenas; - for (size_t i = 0; i < ArraySize(ctx->ScratchArenas); i += 1, arena_ptr += 1) + Arena** conflict_ptr = conflicts; + bool has_conflict = false; + for (size_t j = 0; j < count; j += 1, conflict_ptr += 1) { - Arena** conflict_ptr = conflicts; - bool has_conflict = false; - for (size_t j = 0; j < count; j += 1, conflict_ptr += 1) + if (*arena_ptr == *conflict_ptr) { - if (*arena_ptr == *conflict_ptr) - { - has_conflict = true; - break; - } - } - if (!has_conflict) - { - result = *arena_ptr; + has_conflict = true; break; } } - return result; + if (!has_conflict) + { + result = *arena_ptr; + break; + } } + return result; +} - TempArena scratch_begin(Arena** conflicts, size_t count) - { - return ArenaTempBegin(thread_context_get_scratch(conflicts, count)); - } +TempArena scratch_begin(Arena** conflicts, size_t count) +{ + return ArenaTempBegin(thread_context_get_scratch(conflicts, count)); +} - void scratch_end(TempArena scratch) - { - ArenaTempEnd(scratch); - } +void scratch_end(TempArena scratch) +{ + ArenaTempEnd(scratch); +} -} // namespace Juliet diff --git a/Juliet/src/Core/Thread/win32_thread.cpp b/Juliet/src/Core/Thread/win32_thread.cpp index fe7f236..02a0537 100644 --- a/Juliet/src/Core/Thread/win32_thread.cpp +++ b/Juliet/src/Core/Thread/win32_thread.cpp @@ -1,63 +1,60 @@ -#include +#include #include #include #include -namespace Juliet +uint32 thread_id() { - uint32 thread_id() + uint32 id = GetCurrentThreadId(); + return id; +} + +extern Win32_SetThreadDescription_FuncType* Win32_SetThreadDescription_Func; + +void set_thread_name(String name) +{ + TempArena scratch = scratch_begin(0, 0); + + // New way: + // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription + // Old way: + // https://learn.microsoft.com/fr-fr/previous-versions/visualstudio/visual-studio-2015/debugger/how-to-set-a-thread-name-in-native-code?view=vs-2015&redirectedfrom=MSDN + + if (Win32_SetThreadDescription_Func != nullptr) { - uint32 id = GetCurrentThreadId(); - return id; + String16 name16 = str16_from_8(scratch.Arena, name); + Win32_SetThreadDescription_Func(GetCurrentThread(), (WCHAR*)name16.Str); } - extern Win32_SetThreadDescription_FuncType* Win32_SetThreadDescription_Func; - - void set_thread_name(String name) - { - TempArena scratch = scratch_begin(0, 0); - - // New way: - // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription - // Old way: - // https://learn.microsoft.com/fr-fr/previous-versions/visualstudio/visual-studio-2015/debugger/how-to-set-a-thread-name-in-native-code?view=vs-2015&redirectedfrom=MSDN - - if (Win32_SetThreadDescription_Func != nullptr) - { - String16 name16 = str16_from_8(scratch.Arena, name); - Win32_SetThreadDescription_Func(GetCurrentThread(), (WCHAR*)name16.Str); - } - - String8 name_copy = StringCopy(scratch.Arena, name); + String8 name_copy = StringCopy(scratch.Arena, name); #pragma pack(push, 8) - struct THREADNAME_INFO - { - DWORD dwType; // Must be 0x1000. - LPCSTR szName; // Pointer to name (in user addr space). - DWORD dwThreadID; // Thread ID (-1=caller thread). - DWORD dwFlags; // Reserved for future use, must be zero. - }; + struct THREADNAME_INFO + { + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. + }; #pragma pack(pop) - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = CStr(name_copy); - info.dwThreadID = thread_id(); - info.dwFlags = 0; + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = CStr(name_copy); + info.dwThreadID = thread_id(); + info.dwFlags = 0; #pragma warning(push) #pragma warning(disable : 6320 6322) - __try - { - RaiseException(0x406D1388, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - } + __try + { + RaiseException(0x406D1388, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + } #pragma warning(pop) - scratch_end(scratch); - } + scratch_end(scratch); +} -} // namespace Juliet diff --git a/Juliet/src/Engine/Asset.cpp b/Juliet/src/Engine/Asset.cpp index f3867a3..8b19439 100644 --- a/Juliet/src/Engine/Asset.cpp +++ b/Juliet/src/Engine/Asset.cpp @@ -1,6 +1,3 @@ -#include +#include -namespace Juliet -{ - MeshAssetID LoadMesh([[maybe_unused]] String filename) { return 0; } -} // namespace Juliet +MeshAssetID LoadMesh([[maybe_unused]] String filename) { return 0; } diff --git a/Juliet/src/Engine/Debug/MemoryDebugger.cpp b/Juliet/src/Engine/Debug/MemoryDebugger.cpp index eb24cd5..65e5e9f 100644 --- a/Juliet/src/Engine/Debug/MemoryDebugger.cpp +++ b/Juliet/src/Engine/Debug/MemoryDebugger.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -8,12 +8,9 @@ #if JULIET_DEBUG -namespace Juliet -{ - Arena* GetGlobalArenaListHead(); -} // namespace Juliet +Arena* GetGlobalArenaListHead(); -namespace Juliet::Debug +namespace Debug { namespace { @@ -596,6 +593,6 @@ namespace Juliet::Debug s_ConfirmedHovered = frameHovered; } -} // namespace Juliet::Debug +} // namespace Debug #endif diff --git a/Juliet/src/Engine/Engine.cpp b/Juliet/src/Engine/Engine.cpp index a3ef1a8..4ef7756 100644 --- a/Juliet/src/Engine/Engine.cpp +++ b/Juliet/src/Engine/Engine.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -19,211 +19,208 @@ #include #endif -namespace Juliet +#if JULIET_DEBUG +namespace UnitTest { -#if JULIET_DEBUG - namespace UnitTest + extern void RunUnitTests(); +} +#endif + +namespace +{ + Engine EngineInstance; + + // Initialize systems that depend on graphics/window (after App::Init) + void InitializeDependentSystems() { - extern void RunUnitTests(); + GraphicsDevice* device = EngineInstance.Application->GetGraphicsDevice(); + + if (device) + { + DebugDisplay_Initialize(EngineInstance.PlatformArena, device); + if (Window* window = EngineInstance.Application->GetPlatformWindow()) + { + bool success = InitializeMeshRendererGraphics(device, window); + Assert(success); + (void)(success); + + success = InitializeSkyboxRenderer(device, window); + Assert(success); + (void)(success); + } + } + +#ifdef JULIET_ENABLE_IMGUI + if (NonNullPtr window = EngineInstance.Application->GetPlatformWindow()) + { + ImGuiService::Initialize(window); + ImGui::SetCurrentContext(ImGuiService::GetContext()); + + if (device) + { + ImGuiRenderer_Initialize(device); + + // Run Unit Tests automatically + ImGuiService::RunTests(); + } + } +#endif } -#endif - namespace + // Shutdown systems that were initialized in InitializeDependentSystems + void ShutdownDependentSystems() { - Engine EngineInstance; - - // Initialize systems that depend on graphics/window (after App::Init) - void InitializeDependentSystems() - { - GraphicsDevice* device = EngineInstance.Application->GetGraphicsDevice(); - - if (device) - { - DebugDisplay_Initialize(EngineInstance.PlatformArena, device); - if (Window* window = EngineInstance.Application->GetPlatformWindow()) - { - bool success = InitializeMeshRendererGraphics(device, window); - Assert(success); - (void)(success); - - success = InitializeSkyboxRenderer(device, window); - Assert(success); - (void)(success); - } - } + GraphicsDevice* device = EngineInstance.Application->GetGraphicsDevice(); #ifdef JULIET_ENABLE_IMGUI - if (NonNullPtr window = EngineInstance.Application->GetPlatformWindow()) - { - ImGuiService::Initialize(window); - ImGui::SetCurrentContext(ImGuiService::GetContext()); - - if (device) - { - ImGuiRenderer_Initialize(device); - - // Run Unit Tests automatically - ImGuiService::RunTests(); - } - } + if (device) + { + ImGuiRenderer_Shutdown(device); + } + ImGuiService::Shutdown(); #endif + + // DebugDisplay system + if (device) + { + DebugDisplay_Shutdown(device); + ShutdownSkyboxRenderer(); + ShutdownMeshRendererGraphics(); + } + } + + // Render one frame + void RenderFrame() + { + GraphicsDevice* device = EngineInstance.Application->GetGraphicsDevice(); + Window* window = EngineInstance.Application->GetPlatformWindow(); + + if (!device || !window) + { + return; } - // Shutdown systems that were initialized in InitializeDependentSystems - void ShutdownDependentSystems() + CommandList* cmdList = AcquireCommandList(device, QueueType::Graphics); + if (!cmdList) { - GraphicsDevice* device = EngineInstance.Application->GetGraphicsDevice(); - -#ifdef JULIET_ENABLE_IMGUI - if (device) - { - ImGuiRenderer_Shutdown(device); - } - ImGuiService::Shutdown(); -#endif - - // DebugDisplay system - if (device) - { - DebugDisplay_Shutdown(device); - ShutdownSkyboxRenderer(); - ShutdownMeshRendererGraphics(); - } + return; } - // Render one frame - void RenderFrame() + Texture* swapChainTexture = nullptr; + if (!WaitAndAcquireSwapChainTexture(cmdList, window, &swapChainTexture)) { - GraphicsDevice* device = EngineInstance.Application->GetGraphicsDevice(); - Window* window = EngineInstance.Application->GetPlatformWindow(); - - if (!device || !window) - { - return; - } - - CommandList* cmdList = AcquireCommandList(device, QueueType::Graphics); - if (!cmdList) - { - return; - } - - Texture* swapChainTexture = nullptr; - if (!WaitAndAcquireSwapChainTexture(cmdList, window, &swapChainTexture)) - { - // Swapchain might need resize, submit empty and try again next frame - SubmitCommandLists(cmdList); - return; - } - - if (swapChainTexture) - { - // Prepare debug display data (before render pass) - DebugDisplay_Prepare(cmdList); - - // Get render targets from application - ColorTargetInfo colorInfo = EngineInstance.Application->GetColorTargetInfo(swapChainTexture); - DepthStencilTargetInfo* depthInfo = EngineInstance.Application->GetDepthTargetInfo(); - - RenderPass* pass = BeginRenderPass(cmdList, colorInfo, depthInfo); - - Camera camera = *GetCurrentCamera(); - Matrix viewProjectionMat = Camera_GetViewProjectionMatrix(camera); - - RenderSkybox(cmdList, pass, viewProjectionMat); - RenderMeshes(cmdList, pass, viewProjectionMat); - - // Debug display flush must happen after game rendering - DebugDisplay_Flush(cmdList, pass, camera); - -#ifdef JULIET_ENABLE_IMGUI - // ImGui rendering (always last before EndRenderPass) - ImGuiRenderer_Render(cmdList, pass); -#endif - - EndRenderPass(pass); - } - + // Swapchain might need resize, submit empty and try again next frame SubmitCommandLists(cmdList); + return; } - } // namespace - void InitializeEngine(JulietInit_Flags flags) - { - EngineInstance.PlatformArena = ArenaAllocate({ .ReserveSize = Megabytes(128), .Name = "Platform Arena" }); - EngineInstance.AssetArena = ArenaAllocate({ .ReserveSize = Megabytes(256), .Name = "Asset Arena" }); + if (swapChainTexture) + { + // Prepare debug display data (before render pass) + DebugDisplay_Prepare(cmdList); - InitializeLogManager(); + // Get render targets from application + ColorTargetInfo colorInfo = EngineInstance.Application->GetColorTargetInfo(swapChainTexture); + DepthStencilTargetInfo* depthInfo = EngineInstance.Application->GetDepthTargetInfo(); + + RenderPass* pass = BeginRenderPass(cmdList, colorInfo, depthInfo); + + Camera camera = *GetCurrentCamera(); + Matrix viewProjectionMat = Camera_GetViewProjectionMatrix(camera); + + RenderSkybox(cmdList, pass, viewProjectionMat); + RenderMeshes(cmdList, pass, viewProjectionMat); + + // Debug display flush must happen after game rendering + DebugDisplay_Flush(cmdList, pass, camera); + +#ifdef JULIET_ENABLE_IMGUI + // ImGui rendering (always last before EndRenderPass) + ImGuiRenderer_Render(cmdList, pass); +#endif + + EndRenderPass(pass); + } + + SubmitCommandLists(cmdList); + } +} // namespace + +void InitializeEngine(JulietInit_Flags flags) +{ + EngineInstance.PlatformArena = ArenaAllocate({ .ReserveSize = Megabytes(128), .Name = "Platform Arena" }); + EngineInstance.AssetArena = ArenaAllocate({ .ReserveSize = Megabytes(256), .Name = "Asset Arena" }); + + InitializeLogManager(); #if JULIET_DEBUG - UnitTest::RunUnitTests(); + UnitTest::RunUnitTests(); #endif - InitFilesystem(EngineInstance.PlatformArena); + InitFilesystem(EngineInstance.PlatformArena); - JulietInit(flags); - } + JulietInit(flags); +} - void ShutdownEngine() +void ShutdownEngine() +{ + JulietShutdown(); + + ShutdownFilesystem(); + ShutdownLogManager(); + + ArenaRelease(EngineInstance.AssetArena); + ArenaRelease(EngineInstance.PlatformArena); +} + +void LoadApplication(IApplication& app) +{ + EngineInstance.Application = &app; + + InitializeMeshRenderer(EngineInstance.AssetArena, EngineInstance.PlatformArena); + + EngineInstance.Application->Init(EngineInstance.PlatformArena); + + // Systems depending on Window/GraphicsDevice + InitializeDependentSystems(); +} + +void UnloadApplication() +{ + // Shutdown dependent systems before app shutdown + ShutdownDependentSystems(); + + EngineInstance.Application->Shutdown(); + + ShutdownMeshRenderer(); + + EngineInstance.Application = nullptr; +} + +void RunEngine() +{ + while (EngineInstance.Application->IsRunning()) { - JulietShutdown(); - - ShutdownFilesystem(); - ShutdownLogManager(); - - ArenaRelease(EngineInstance.AssetArena); - ArenaRelease(EngineInstance.PlatformArena); - } - - void LoadApplication(IApplication& app) - { - EngineInstance.Application = &app; - - InitializeMeshRenderer(EngineInstance.AssetArena, EngineInstance.PlatformArena); - - EngineInstance.Application->Init(EngineInstance.PlatformArena); - - // Systems depending on Window/GraphicsDevice - InitializeDependentSystems(); - } - - void UnloadApplication() - { - // Shutdown dependent systems before app shutdown - ShutdownDependentSystems(); - - EngineInstance.Application->Shutdown(); - - ShutdownMeshRenderer(); - - EngineInstance.Application = nullptr; - } - - void RunEngine() - { - while (EngineInstance.Application->IsRunning()) - { #ifdef JULIET_ENABLE_IMGUI - ImGuiRenderer_NewFrame(); + ImGuiRenderer_NewFrame(); #endif - Time::ComputeDeltaTime(); + Time::ComputeDeltaTime(); - const float deltaTime = Time::GetDeltaTime(); + const float deltaTime = Time::GetDeltaTime(); - Events_NewFrame(deltaTime); + Events_NewFrame(deltaTime); - // Logic tick - EngineInstance.Application->Update(deltaTime); + // Logic tick + EngineInstance.Application->Update(deltaTime); - // Render tick - RenderFrame(); - } + // Render tick + RenderFrame(); } +} - Arena* GetPlatformArena() - { - NonNullPtr arena = EngineInstance.PlatformArena; - return arena.Get(); - } -} // namespace Juliet +Arena* GetPlatformArena() +{ + NonNullPtr arena = EngineInstance.PlatformArena; + return arena.Get(); +} diff --git a/Juliet/src/Graphics/Camera.cpp b/Juliet/src/Graphics/Camera.cpp index 5dc3c35..9a30b63 100644 --- a/Juliet/src/Graphics/Camera.cpp +++ b/Juliet/src/Graphics/Camera.cpp @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include @@ -7,66 +7,63 @@ #include #include -namespace Juliet +namespace { - namespace + + Camera kDefaultCameraTemplate = { + .Index = 0, + .Position = { 25.0f, 0.0f, 12.5f }, + .Target = { cosf(0.f) * cosf(0.f), sinf(0.f) * cosf(0.f), sinf(0.f) }, + .Up = { 0.0f, 0.0f, 1.0f }, + .FOV = 1.047f, + .AspectRatio = 1200.0f / 800.0f, + .NearPlane = 0.1f, + .FarPlane = 1000.0f, + }; // namespace + + size_t CameraAmount = 0; + Camera* CameraArray = nullptr; + Camera* CurrentCamera = nullptr; +} // namespace + +void ReserveCamera(size_t amount) +{ + Assert(CameraAmount == 0); + Assert(amount > 0); + + CameraAmount = amount; + + CameraArray = ArenaPushArray(GetPlatformArena(), CameraAmount JULIET_DEBUG_PARAM("Camera Array")); + + for (index_t index = 0; index < CameraAmount; ++index) { - - Camera kDefaultCameraTemplate = { - .Index = 0, - .Position = { 25.0f, 0.0f, 12.5f }, - .Target = { cosf(0.f) * cosf(0.f), sinf(0.f) * cosf(0.f), sinf(0.f) }, - .Up = { 0.0f, 0.0f, 1.0f }, - .FOV = 1.047f, - .AspectRatio = 1200.0f / 800.0f, - .NearPlane = 0.1f, - .FarPlane = 1000.0f, - }; // namespace - - size_t CameraAmount = 0; - Camera* CameraArray = nullptr; - Camera* CurrentCamera = nullptr; - } // namespace - - void ReserveCamera(size_t amount) - { - Assert(CameraAmount == 0); - Assert(amount > 0); - - CameraAmount = amount; - - CameraArray = ArenaPushArray(GetPlatformArena(), CameraAmount JULIET_DEBUG_PARAM("Camera Array")); - - for (index_t index = 0; index < CameraAmount; ++index) - { - Camera* cam = CameraArray + index; - *cam = kDefaultCameraTemplate; - cam->Index = index; - } - - CurrentCamera = &CameraArray[0]; + Camera* cam = CameraArray + index; + *cam = kDefaultCameraTemplate; + cam->Index = index; } - Camera* GetCurrentCamera() - { - if (CameraAmount == 0) - { - ReserveCamera(1); - } + CurrentCamera = &CameraArray[0]; +} - NonNullPtr cam = CurrentCamera; - return cam.Get(); +Camera* GetCurrentCamera() +{ + if (CameraAmount == 0) + { + ReserveCamera(1); } - void SetCurrentCamera(index_t index) + NonNullPtr cam = CurrentCamera; + return cam.Get(); +} + +void SetCurrentCamera(index_t index) +{ + if (CameraAmount == 0) { - if (CameraAmount == 0) - { - ReserveCamera(1); - } - - Assert(index <= CameraAmount); - - CurrentCamera = CameraArray + index; + ReserveCamera(1); } -} // namespace Juliet + + Assert(index <= CameraAmount); + + CurrentCamera = CameraArray + index; +} diff --git a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp index c77c1e6..e5fcdba 100644 --- a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp @@ -38,1127 +38,1121 @@ // TODO : Use LoadLibrary and not link to the lib. Allows failing earlier if Dx12 is not installed for some reason // + Will load the dll when needed // This will prevent us from using IID_ variables as they are defined in dxguid.lib -namespace Juliet +namespace { - namespace - { - struct D3D12GraphicsRootSignature; - struct D3D12GraphicsPipeline; - struct D3D12Texture; - struct D3D12TextureSubresource; - struct D3D12Fence; - struct D3D12CommandList; - struct D3D12StagingDescriptorPool; + struct D3D12GraphicsRootSignature; + struct D3D12GraphicsPipeline; + struct D3D12Texture; + struct D3D12TextureSubresource; + struct D3D12Fence; + struct D3D12CommandList; + struct D3D12StagingDescriptorPool; - // Note: This is the highest my Gfx Card supports (5700XT) - // https://en.wikipedia.org/wiki/Feature_levels_in_Direct3D#Direct3D_12 - // 12_2 Adds RayTracing and others feature supported by RDNA2 and greater and Gefore 20xx and greater - constexpr D3D_FEATURE_LEVEL kD3DFeatureLevel = D3D_FEATURE_LEVEL_12_1; - constexpr auto kD3DFeatureLevelStr = "12_1"; - constexpr size_t kStagingHeapDescriptorExpectedCount = 1024; - constexpr size_t kMaxTexturePerCommandList = 1024; - constexpr size_t kMaxGraphicsPipelinePerCommandList = 1024; - constexpr size_t kMaxPresentDataPerCommandList = 1; - constexpr size_t kMaxCommandListCount = 4; + // Note: This is the highest my Gfx Card supports (5700XT) + // https://en.wikipedia.org/wiki/Feature_levels_in_Direct3D#Direct3D_12 + // 12_2 Adds RayTracing and others feature supported by RDNA2 and greater and Gefore 20xx and greater + constexpr D3D_FEATURE_LEVEL kD3DFeatureLevel = D3D_FEATURE_LEVEL_12_1; + constexpr auto kD3DFeatureLevelStr = "12_1"; + constexpr size_t kStagingHeapDescriptorExpectedCount = 1024; + constexpr size_t kMaxTexturePerCommandList = 1024; + constexpr size_t kMaxGraphicsPipelinePerCommandList = 1024; + constexpr size_t kMaxPresentDataPerCommandList = 1; + constexpr size_t kMaxCommandListCount = 4; - index_t CommandListID = 0; + index_t CommandListID = 0; - uint32 JulietToD3D12_SampleCount[] = { - 1, // MSAA 1x - 2, // MSAA 2x - 4, // MSAA 4x - 8, // MSAA 8x - }; - - DXGI_COLOR_SPACE_TYPE SwapchainCompositionToColorSpace[] = { - DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // SDR - DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // SDR_LINEAR - DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709, // HDR_EXTENDED_LINEAR - DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 // HDR10_ST2084 - }; - - DXGI_FORMAT SwapchainCompositionToTextureFormat[] = { - DXGI_FORMAT_B8G8R8A8_UNORM, // SDR - DXGI_FORMAT_B8G8R8A8_UNORM, // SDR_LINEAR (NOTE: The RTV uses the sRGB format) - DXGI_FORMAT_R16G16B16A16_FLOAT, // HDR_EXTENDED_LINEAR - DXGI_FORMAT_R10G10B10A2_UNORM, // HDR10_ST2084 - }; - - TextureFormat SwapchainCompositionToJulietTextureFormat[] = { - TextureFormat::B8G8R8A8_UNORM, // SDR - TextureFormat::B8G8R8A8_UNORM_SRGB, // SDR_LINEAR - TextureFormat::R16G16B16A16_FLOAT, // HDR_EXTENDED_LINEAR - TextureFormat::R10G10B10A2_UNORM, // HDR10_ST2084 - }; - - DXGI_FORMAT JulietToD3D12_TextureFormat[] = { - DXGI_FORMAT_UNKNOWN, // INVALID - DXGI_FORMAT_A8_UNORM, // A8_UNORM - DXGI_FORMAT_R8_UNORM, // R8_UNORM - DXGI_FORMAT_R8G8_UNORM, // R8G8_UNORM - DXGI_FORMAT_R8G8B8A8_UNORM, // R8G8B8A8_UNORM - DXGI_FORMAT_R16_UNORM, // R16_UNORM - DXGI_FORMAT_R16G16_UNORM, // R16G16_UNORM - DXGI_FORMAT_R16G16B16A16_UNORM, // R16G16B16A16_UNORM - DXGI_FORMAT_R10G10B10A2_UNORM, // R10G10B10A2_UNORM - DXGI_FORMAT_B5G6R5_UNORM, // B5G6R5_UNORM - DXGI_FORMAT_B5G5R5A1_UNORM, // B5G5R5A1_UNORM - DXGI_FORMAT_B4G4R4A4_UNORM, // B4G4R4A4_UNORM - DXGI_FORMAT_B8G8R8A8_UNORM, // B8G8R8A8_UNORM - DXGI_FORMAT_BC1_UNORM, // BC1_UNORM - DXGI_FORMAT_BC2_UNORM, // BC2_UNORM - DXGI_FORMAT_BC3_UNORM, // BC3_UNORM - DXGI_FORMAT_BC4_UNORM, // BC4_UNORM - DXGI_FORMAT_BC5_UNORM, // BC5_UNORM - DXGI_FORMAT_BC7_UNORM, // BC7_UNORM - DXGI_FORMAT_BC6H_SF16, // BC6H_FLOAT - DXGI_FORMAT_BC6H_UF16, // BC6H_UFLOAT - DXGI_FORMAT_R8_SNORM, // R8_SNORM - DXGI_FORMAT_R8G8_SNORM, // R8G8_SNORM - DXGI_FORMAT_R8G8B8A8_SNORM, // R8G8B8A8_SNORM - DXGI_FORMAT_R16_SNORM, // R16_SNORM - DXGI_FORMAT_R16G16_SNORM, // R16G16_SNORM - DXGI_FORMAT_R16G16B16A16_SNORM, // R16G16B16A16_SNORM - DXGI_FORMAT_R16_FLOAT, // R16_FLOAT - DXGI_FORMAT_R16G16_FLOAT, // R16G16_FLOAT - DXGI_FORMAT_R16G16B16A16_FLOAT, // R16G16B16A16_FLOAT - DXGI_FORMAT_R32_FLOAT, // R32_FLOAT - DXGI_FORMAT_R32G32_FLOAT, // R32G32_FLOAT - DXGI_FORMAT_R32G32B32A32_FLOAT, // R32G32B32A32_FLOAT - DXGI_FORMAT_R11G11B10_FLOAT, // R11G11B10_UFLOAT - DXGI_FORMAT_R8_UINT, // R8_UINT - DXGI_FORMAT_R8G8_UINT, // R8G8_UINT - DXGI_FORMAT_R8G8B8A8_UINT, // R8G8B8A8_UINT - DXGI_FORMAT_R16_UINT, // R16_UINT - DXGI_FORMAT_R16G16_UINT, // R16G16_UINT - DXGI_FORMAT_R16G16B16A16_UINT, // R16G16B16A16_UINT - DXGI_FORMAT_R32_UINT, // R32_UINT - DXGI_FORMAT_R32G32_UINT, // R32G32_UINT - DXGI_FORMAT_R32G32B32A32_UINT, // R32G32B32A32_UINT - DXGI_FORMAT_R8_SINT, // R8_INT - DXGI_FORMAT_R8G8_SINT, // R8G8_INT - DXGI_FORMAT_R8G8B8A8_SINT, // R8G8B8A8_INT - DXGI_FORMAT_R16_SINT, // R16_INT - DXGI_FORMAT_R16G16_SINT, // R16G16_INT - DXGI_FORMAT_R16G16B16A16_SINT, // R16G16B16A16_INT - DXGI_FORMAT_R32_SINT, // R32_INT - DXGI_FORMAT_R32G32_SINT, // R32G32_INT - DXGI_FORMAT_R32G32B32A32_SINT, // R32G32B32A32_INT - DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, // R8G8B8A8_UNORM_SRGB - DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, // B8G8R8A8_UNORM_SRGB - DXGI_FORMAT_BC1_UNORM_SRGB, // BC1_UNORM_SRGB - DXGI_FORMAT_BC2_UNORM_SRGB, // BC2_UNORM_SRGB - DXGI_FORMAT_BC3_UNORM_SRGB, // BC3_UNORM_SRGB - DXGI_FORMAT_BC7_UNORM_SRGB, // BC7_UNORM_SRGB - DXGI_FORMAT_R16_TYPELESS, // D16_UNORM - DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM - DXGI_FORMAT_R32_TYPELESS, // D32_FLOAT - DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM_S8_UINT - DXGI_FORMAT_R32G8X24_TYPELESS, // D32_FLOAT_S8_UINT - DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_4x4_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_5x4_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_5x5_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_6x5_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_6x6_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_8x5_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_8x6_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_8x8_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_10x5_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_10x6_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_10x8_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_10x10_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT - }; - static_assert(sizeof(JulietToD3D12_TextureFormat) / sizeof(JulietToD3D12_TextureFormat[0]) == - ToUnderlying(TextureFormat::Count)); - - DXGI_FORMAT JulietToD3D12_DepthFormat[] = { - DXGI_FORMAT_UNKNOWN, // INVALID - DXGI_FORMAT_UNKNOWN, // A8_UNORM - DXGI_FORMAT_UNKNOWN, // R8_UNORM - DXGI_FORMAT_UNKNOWN, // R8G8_UNORM - DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UNORM - DXGI_FORMAT_UNKNOWN, // R16_UNORM - DXGI_FORMAT_UNKNOWN, // R16G16_UNORM - DXGI_FORMAT_UNKNOWN, // R16G16B16A16_UNORM - DXGI_FORMAT_UNKNOWN, // R10G10B10A2_UNORM - DXGI_FORMAT_UNKNOWN, // B5G6R5_UNORM - DXGI_FORMAT_UNKNOWN, // B5G5R5A1_UNORM - DXGI_FORMAT_UNKNOWN, // B4G4R4A4_UNORM - DXGI_FORMAT_UNKNOWN, // B8G8R8A8_UNORM - DXGI_FORMAT_UNKNOWN, // BC1_UNORM - DXGI_FORMAT_UNKNOWN, // BC2_UNORM - DXGI_FORMAT_UNKNOWN, // BC3_UNORM - DXGI_FORMAT_UNKNOWN, // BC4_UNORM - DXGI_FORMAT_UNKNOWN, // BC5_UNORM - DXGI_FORMAT_UNKNOWN, // BC7_UNORM - DXGI_FORMAT_UNKNOWN, // BC6H_FLOAT - DXGI_FORMAT_UNKNOWN, // BC6H_UFLOAT - DXGI_FORMAT_UNKNOWN, // R8_SNORM - DXGI_FORMAT_UNKNOWN, // R8G8_SNORM - DXGI_FORMAT_UNKNOWN, // R8G8B8A8_SNORM - DXGI_FORMAT_UNKNOWN, // R16_SNORM - DXGI_FORMAT_UNKNOWN, // R16G16_SNORM - DXGI_FORMAT_UNKNOWN, // R16G16B16A16_SNORM - DXGI_FORMAT_UNKNOWN, // R16_FLOAT - DXGI_FORMAT_UNKNOWN, // R16G16_FLOAT - DXGI_FORMAT_UNKNOWN, // R16G16B16A16_FLOAT - DXGI_FORMAT_UNKNOWN, // R32_FLOAT - DXGI_FORMAT_UNKNOWN, // R32G32_FLOAT - DXGI_FORMAT_UNKNOWN, // R32G32B32A32_FLOAT - DXGI_FORMAT_UNKNOWN, // R11G11B10_UFLOAT - DXGI_FORMAT_UNKNOWN, // R8_UINT - DXGI_FORMAT_UNKNOWN, // R8G8_UINT - DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UINT - DXGI_FORMAT_UNKNOWN, // R16_UINT - DXGI_FORMAT_UNKNOWN, // R16G16_UINT - DXGI_FORMAT_UNKNOWN, // R16G16B16A16_UINT - DXGI_FORMAT_UNKNOWN, // R32_UINT - DXGI_FORMAT_UNKNOWN, // R32G32_UINT - DXGI_FORMAT_UNKNOWN, // R32G32B32A32_UINT - DXGI_FORMAT_UNKNOWN, // R8_INT - DXGI_FORMAT_UNKNOWN, // R8G8_INT - DXGI_FORMAT_UNKNOWN, // R8G8B8A8_INT - DXGI_FORMAT_UNKNOWN, // R16_INT - DXGI_FORMAT_UNKNOWN, // R16G16_INT - DXGI_FORMAT_UNKNOWN, // R16G16B16A16_INT - DXGI_FORMAT_UNKNOWN, // R32_INT - DXGI_FORMAT_UNKNOWN, // R32G32_INT - DXGI_FORMAT_UNKNOWN, // R32G32B32A32_INT - DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // B8G8R8A8_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // BC1_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // BC2_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // BC3_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // BC7_UNORM_SRGB - DXGI_FORMAT_D16_UNORM, // D16_UNORM - DXGI_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM - DXGI_FORMAT_D32_FLOAT, // D32_FLOAT - DXGI_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM_S8_UINT - DXGI_FORMAT_D32_FLOAT_S8X24_UINT, // D32_FLOAT_S8_UINT - DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_4x4_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_5x4_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_5x5_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_6x5_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_6x6_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_8x5_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_8x6_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_8x8_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_10x5_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_10x6_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_10x8_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_10x10_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT - }; - static_assert(sizeof(JulietToD3D12_DepthFormat) / sizeof(JulietToD3D12_DepthFormat[0]) == ToUnderlying(TextureFormat::Count)); - - // clang-format off - D3D12_INPUT_CLASSIFICATION JulietToD3D12_InputRate[] = - { - D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, // VERTEX - D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA // INSTANCE - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_InputRate) / sizeof(JulietToD3D12_InputRate[0]) == ToUnderlying(VertexInputRate::Count)); - - // clang-format off - D3D12_CULL_MODE JulietToD3D12_CullMode[] = - { - D3D12_CULL_MODE_NONE, - D3D12_CULL_MODE_FRONT, - D3D12_CULL_MODE_BACK - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_CullMode) / sizeof(JulietToD3D12_CullMode[0]) == ToUnderlying(CullMode::Count)); - - // clang-format off - D3D12_FILL_MODE JulietToD3D12_FillMode[] = - { - D3D12_FILL_MODE_SOLID, - D3D12_FILL_MODE_WIREFRAME - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_FillMode) / sizeof(JulietToD3D12_FillMode[0]) == ToUnderlying(FillMode::Count)); - - DXGI_FORMAT JulietToD3D12_VertexFormat[] = { - DXGI_FORMAT_UNKNOWN, // Unknown - DXGI_FORMAT_R32_SINT, // Int - DXGI_FORMAT_R32G32_SINT, // Int2 - DXGI_FORMAT_R32G32B32_SINT, // Int3 - DXGI_FORMAT_R32G32B32A32_SINT, // Int4 - DXGI_FORMAT_R32_UINT, // UInt - DXGI_FORMAT_R32G32_UINT, // UInt2 - DXGI_FORMAT_R32G32B32_UINT, // UInt3 - DXGI_FORMAT_R32G32B32A32_UINT, // UInt4 - DXGI_FORMAT_R32_FLOAT, // Float - DXGI_FORMAT_R32G32_FLOAT, // Float2 - DXGI_FORMAT_R32G32B32_FLOAT, // Float3 - DXGI_FORMAT_R32G32B32A32_FLOAT, // Float4 - DXGI_FORMAT_R8G8_SINT, // Byte2 - DXGI_FORMAT_R8G8B8A8_SINT, // Byte4 - DXGI_FORMAT_R8G8_UINT, // UByte2 - DXGI_FORMAT_R8G8B8A8_UINT, // UByte4 - DXGI_FORMAT_R8G8_SNORM, // Byte2_Norm - DXGI_FORMAT_R8G8B8A8_SNORM, // Byte4_Norm - DXGI_FORMAT_R8G8_UNORM, // UByte2_Norm - DXGI_FORMAT_R8G8B8A8_UNORM, // UByte4_Norm - DXGI_FORMAT_R16G16_SINT, // Short2 - DXGI_FORMAT_R16G16B16A16_SINT, // Short4 - DXGI_FORMAT_R16G16_UINT, // UShort2 - DXGI_FORMAT_R16G16B16A16_UINT, // UShort4 - DXGI_FORMAT_R16G16_SNORM, // Short2_Norm - DXGI_FORMAT_R16G16B16A16_SNORM, // Short4_Norm - DXGI_FORMAT_R16G16_UNORM, // UShort2_Norm - DXGI_FORMAT_R16G16B16A16_UNORM, // UShort4_Norm - DXGI_FORMAT_R16G16_FLOAT, // Half2 - DXGI_FORMAT_R16G16B16A16_FLOAT // Half4 - }; - static_assert(sizeof(JulietToD3D12_VertexFormat) / sizeof(JulietToD3D12_VertexFormat[0]) == - ToUnderlying(VertexElementFormat::Count)); - - // clang-format off - D3D12_PRIMITIVE_TOPOLOGY_TYPE JulietToD3D12_PrimitiveTopologyType[] = { - D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, - D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, - D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE, - D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE, - D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_PrimitiveTopologyType) / sizeof(JulietToD3D12_PrimitiveTopologyType[0]) == - ToUnderlying(PrimitiveType::Count)); - - // clang-format off - D3D12_BLEND JulietToD3D12_BlendFactor[] = - { - D3D12_BLEND_ZERO, - D3D12_BLEND_ZERO, - D3D12_BLEND_ONE, - D3D12_BLEND_SRC_COLOR, - D3D12_BLEND_INV_SRC_COLOR, - D3D12_BLEND_DEST_COLOR, - D3D12_BLEND_INV_DEST_COLOR, - D3D12_BLEND_SRC_ALPHA, - D3D12_BLEND_INV_SRC_ALPHA, - D3D12_BLEND_DEST_ALPHA, - D3D12_BLEND_INV_DEST_ALPHA, - D3D12_BLEND_BLEND_FACTOR, - D3D12_BLEND_INV_BLEND_FACTOR, - D3D12_BLEND_SRC_ALPHA_SAT, - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_BlendFactor) / sizeof(JulietToD3D12_BlendFactor[0]) == ToUnderlying(BlendFactor::Count)); - - // clang-format off - D3D12_BLEND JulietToD3D12_BlendFactorAlpha[] = - { - D3D12_BLEND_ZERO, - D3D12_BLEND_ZERO, - D3D12_BLEND_ONE, - D3D12_BLEND_SRC_ALPHA, - D3D12_BLEND_INV_SRC_ALPHA, - D3D12_BLEND_DEST_ALPHA, - D3D12_BLEND_INV_DEST_ALPHA, - D3D12_BLEND_SRC_ALPHA, - D3D12_BLEND_INV_SRC_ALPHA, - D3D12_BLEND_DEST_ALPHA, - D3D12_BLEND_INV_DEST_ALPHA, - D3D12_BLEND_BLEND_FACTOR, - D3D12_BLEND_INV_BLEND_FACTOR, - D3D12_BLEND_SRC_ALPHA_SAT, - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_BlendFactorAlpha) / sizeof(JulietToD3D12_BlendFactorAlpha[0]) == - ToUnderlying(BlendFactor::Count)); - - // clang-format off - D3D12_BLEND_OP JulietToD3D12_BlendOperation[] = - { - D3D12_BLEND_OP_ADD, - D3D12_BLEND_OP_ADD, - D3D12_BLEND_OP_SUBTRACT, - D3D12_BLEND_OP_REV_SUBTRACT, - D3D12_BLEND_OP_MIN, - D3D12_BLEND_OP_MAX - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_BlendOperation) / sizeof(JulietToD3D12_BlendOperation[0]) == - ToUnderlying(BlendOperation::Count)); - - // clang-format off - D3D12_COMPARISON_FUNC JulietToD3D12_CompareOperation[] = - { - D3D12_COMPARISON_FUNC_NEVER, - D3D12_COMPARISON_FUNC_NEVER, - D3D12_COMPARISON_FUNC_LESS, - D3D12_COMPARISON_FUNC_EQUAL, - D3D12_COMPARISON_FUNC_LESS_EQUAL, - D3D12_COMPARISON_FUNC_GREATER, - D3D12_COMPARISON_FUNC_NOT_EQUAL, - D3D12_COMPARISON_FUNC_GREATER_EQUAL, - D3D12_COMPARISON_FUNC_ALWAYS - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_CompareOperation) / sizeof(JulietToD3D12_CompareOperation[0]) == - ToUnderlying(CompareOperation::Count)); - - // clang-format off - D3D12_STENCIL_OP JulietToD3D12_StencilOperation[] = - { - D3D12_STENCIL_OP_KEEP, - D3D12_STENCIL_OP_KEEP, - D3D12_STENCIL_OP_ZERO, - D3D12_STENCIL_OP_REPLACE, - D3D12_STENCIL_OP_INCR_SAT, - D3D12_STENCIL_OP_DECR_SAT, - D3D12_STENCIL_OP_INVERT, - D3D12_STENCIL_OP_INCR, - D3D12_STENCIL_OP_DECR - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_StencilOperation) / sizeof(JulietToD3D12_StencilOperation[0]) == - ToUnderlying(StencilOperation::Count)); - - // clang-format off - D3D12_PRIMITIVE_TOPOLOGY JulietToD3D12_PrimitiveType[] = - { - D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, - D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, - D3D_PRIMITIVE_TOPOLOGY_LINELIST, - D3D_PRIMITIVE_TOPOLOGY_LINESTRIP, - D3D_PRIMITIVE_TOPOLOGY_POINTLIST + uint32 JulietToD3D12_SampleCount[] = { + 1, // MSAA 1x + 2, // MSAA 2x + 4, // MSAA 4x + 8, // MSAA 8x }; - // clang-format on - static_assert(sizeof(JulietToD3D12_PrimitiveType) / sizeof(JulietToD3D12_PrimitiveType[0]) == - ToUnderlying(PrimitiveType::Count)); - enum class RootParameters : uint8 - { - Constants32Bits, - Count, - }; + DXGI_COLOR_SPACE_TYPE SwapchainCompositionToColorSpace[] = { + DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // SDR + DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // SDR_LINEAR + DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709, // HDR_EXTENDED_LINEAR + DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 // HDR10_ST2084 + }; - struct D3D12TextureContainer - { - TextureHeader Header; + DXGI_FORMAT SwapchainCompositionToTextureFormat[] = { + DXGI_FORMAT_B8G8R8A8_UNORM, // SDR + DXGI_FORMAT_B8G8R8A8_UNORM, // SDR_LINEAR (NOTE: The RTV uses the sRGB format) + DXGI_FORMAT_R16G16B16A16_FLOAT, // HDR_EXTENDED_LINEAR + DXGI_FORMAT_R10G10B10A2_UNORM, // HDR10_ST2084 + }; - D3D12Texture* ActiveTexture; - D3D12Texture** Textures; - uint32 Capacity; - uint32 Count; + TextureFormat SwapchainCompositionToJulietTextureFormat[] = { + TextureFormat::B8G8R8A8_UNORM, // SDR + TextureFormat::B8G8R8A8_UNORM_SRGB, // SDR_LINEAR + TextureFormat::R16G16B16A16_FLOAT, // HDR_EXTENDED_LINEAR + TextureFormat::R10G10B10A2_UNORM, // HDR10_ST2084 + }; - // Note: Swapchain images cannot be cycled - bool CanBeCycled; + DXGI_FORMAT JulietToD3D12_TextureFormat[] = { + DXGI_FORMAT_UNKNOWN, // INVALID + DXGI_FORMAT_A8_UNORM, // A8_UNORM + DXGI_FORMAT_R8_UNORM, // R8_UNORM + DXGI_FORMAT_R8G8_UNORM, // R8G8_UNORM + DXGI_FORMAT_R8G8B8A8_UNORM, // R8G8B8A8_UNORM + DXGI_FORMAT_R16_UNORM, // R16_UNORM + DXGI_FORMAT_R16G16_UNORM, // R16G16_UNORM + DXGI_FORMAT_R16G16B16A16_UNORM, // R16G16B16A16_UNORM + DXGI_FORMAT_R10G10B10A2_UNORM, // R10G10B10A2_UNORM + DXGI_FORMAT_B5G6R5_UNORM, // B5G6R5_UNORM + DXGI_FORMAT_B5G5R5A1_UNORM, // B5G5R5A1_UNORM + DXGI_FORMAT_B4G4R4A4_UNORM, // B4G4R4A4_UNORM + DXGI_FORMAT_B8G8R8A8_UNORM, // B8G8R8A8_UNORM + DXGI_FORMAT_BC1_UNORM, // BC1_UNORM + DXGI_FORMAT_BC2_UNORM, // BC2_UNORM + DXGI_FORMAT_BC3_UNORM, // BC3_UNORM + DXGI_FORMAT_BC4_UNORM, // BC4_UNORM + DXGI_FORMAT_BC5_UNORM, // BC5_UNORM + DXGI_FORMAT_BC7_UNORM, // BC7_UNORM + DXGI_FORMAT_BC6H_SF16, // BC6H_FLOAT + DXGI_FORMAT_BC6H_UF16, // BC6H_UFLOAT + DXGI_FORMAT_R8_SNORM, // R8_SNORM + DXGI_FORMAT_R8G8_SNORM, // R8G8_SNORM + DXGI_FORMAT_R8G8B8A8_SNORM, // R8G8B8A8_SNORM + DXGI_FORMAT_R16_SNORM, // R16_SNORM + DXGI_FORMAT_R16G16_SNORM, // R16G16_SNORM + DXGI_FORMAT_R16G16B16A16_SNORM, // R16G16B16A16_SNORM + DXGI_FORMAT_R16_FLOAT, // R16_FLOAT + DXGI_FORMAT_R16G16_FLOAT, // R16G16_FLOAT + DXGI_FORMAT_R16G16B16A16_FLOAT, // R16G16B16A16_FLOAT + DXGI_FORMAT_R32_FLOAT, // R32_FLOAT + DXGI_FORMAT_R32G32_FLOAT, // R32G32_FLOAT + DXGI_FORMAT_R32G32B32A32_FLOAT, // R32G32B32A32_FLOAT + DXGI_FORMAT_R11G11B10_FLOAT, // R11G11B10_UFLOAT + DXGI_FORMAT_R8_UINT, // R8_UINT + DXGI_FORMAT_R8G8_UINT, // R8G8_UINT + DXGI_FORMAT_R8G8B8A8_UINT, // R8G8B8A8_UINT + DXGI_FORMAT_R16_UINT, // R16_UINT + DXGI_FORMAT_R16G16_UINT, // R16G16_UINT + DXGI_FORMAT_R16G16B16A16_UINT, // R16G16B16A16_UINT + DXGI_FORMAT_R32_UINT, // R32_UINT + DXGI_FORMAT_R32G32_UINT, // R32G32_UINT + DXGI_FORMAT_R32G32B32A32_UINT, // R32G32B32A32_UINT + DXGI_FORMAT_R8_SINT, // R8_INT + DXGI_FORMAT_R8G8_SINT, // R8G8_INT + DXGI_FORMAT_R8G8B8A8_SINT, // R8G8B8A8_INT + DXGI_FORMAT_R16_SINT, // R16_INT + DXGI_FORMAT_R16G16_SINT, // R16G16_INT + DXGI_FORMAT_R16G16B16A16_SINT, // R16G16B16A16_INT + DXGI_FORMAT_R32_SINT, // R32_INT + DXGI_FORMAT_R32G32_SINT, // R32G32_INT + DXGI_FORMAT_R32G32B32A32_SINT, // R32G32B32A32_INT + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, // R8G8B8A8_UNORM_SRGB + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, // B8G8R8A8_UNORM_SRGB + DXGI_FORMAT_BC1_UNORM_SRGB, // BC1_UNORM_SRGB + DXGI_FORMAT_BC2_UNORM_SRGB, // BC2_UNORM_SRGB + DXGI_FORMAT_BC3_UNORM_SRGB, // BC3_UNORM_SRGB + DXGI_FORMAT_BC7_UNORM_SRGB, // BC7_UNORM_SRGB + DXGI_FORMAT_R16_TYPELESS, // D16_UNORM + DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM + DXGI_FORMAT_R32_TYPELESS, // D32_FLOAT + DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM_S8_UINT + DXGI_FORMAT_R32G8X24_TYPELESS, // D32_FLOAT_S8_UINT + DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_4x4_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_5x4_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_5x5_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_6x5_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_6x6_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_8x5_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_8x6_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_8x8_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_10x5_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_10x6_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_10x8_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_10x10_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT + }; + static_assert(sizeof(JulietToD3D12_TextureFormat) / sizeof(JulietToD3D12_TextureFormat[0]) == ToUnderlying(TextureFormat::Count)); + + DXGI_FORMAT JulietToD3D12_DepthFormat[] = { + DXGI_FORMAT_UNKNOWN, // INVALID + DXGI_FORMAT_UNKNOWN, // A8_UNORM + DXGI_FORMAT_UNKNOWN, // R8_UNORM + DXGI_FORMAT_UNKNOWN, // R8G8_UNORM + DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UNORM + DXGI_FORMAT_UNKNOWN, // R16_UNORM + DXGI_FORMAT_UNKNOWN, // R16G16_UNORM + DXGI_FORMAT_UNKNOWN, // R16G16B16A16_UNORM + DXGI_FORMAT_UNKNOWN, // R10G10B10A2_UNORM + DXGI_FORMAT_UNKNOWN, // B5G6R5_UNORM + DXGI_FORMAT_UNKNOWN, // B5G5R5A1_UNORM + DXGI_FORMAT_UNKNOWN, // B4G4R4A4_UNORM + DXGI_FORMAT_UNKNOWN, // B8G8R8A8_UNORM + DXGI_FORMAT_UNKNOWN, // BC1_UNORM + DXGI_FORMAT_UNKNOWN, // BC2_UNORM + DXGI_FORMAT_UNKNOWN, // BC3_UNORM + DXGI_FORMAT_UNKNOWN, // BC4_UNORM + DXGI_FORMAT_UNKNOWN, // BC5_UNORM + DXGI_FORMAT_UNKNOWN, // BC7_UNORM + DXGI_FORMAT_UNKNOWN, // BC6H_FLOAT + DXGI_FORMAT_UNKNOWN, // BC6H_UFLOAT + DXGI_FORMAT_UNKNOWN, // R8_SNORM + DXGI_FORMAT_UNKNOWN, // R8G8_SNORM + DXGI_FORMAT_UNKNOWN, // R8G8B8A8_SNORM + DXGI_FORMAT_UNKNOWN, // R16_SNORM + DXGI_FORMAT_UNKNOWN, // R16G16_SNORM + DXGI_FORMAT_UNKNOWN, // R16G16B16A16_SNORM + DXGI_FORMAT_UNKNOWN, // R16_FLOAT + DXGI_FORMAT_UNKNOWN, // R16G16_FLOAT + DXGI_FORMAT_UNKNOWN, // R16G16B16A16_FLOAT + DXGI_FORMAT_UNKNOWN, // R32_FLOAT + DXGI_FORMAT_UNKNOWN, // R32G32_FLOAT + DXGI_FORMAT_UNKNOWN, // R32G32B32A32_FLOAT + DXGI_FORMAT_UNKNOWN, // R11G11B10_UFLOAT + DXGI_FORMAT_UNKNOWN, // R8_UINT + DXGI_FORMAT_UNKNOWN, // R8G8_UINT + DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UINT + DXGI_FORMAT_UNKNOWN, // R16_UINT + DXGI_FORMAT_UNKNOWN, // R16G16_UINT + DXGI_FORMAT_UNKNOWN, // R16G16B16A16_UINT + DXGI_FORMAT_UNKNOWN, // R32_UINT + DXGI_FORMAT_UNKNOWN, // R32G32_UINT + DXGI_FORMAT_UNKNOWN, // R32G32B32A32_UINT + DXGI_FORMAT_UNKNOWN, // R8_INT + DXGI_FORMAT_UNKNOWN, // R8G8_INT + DXGI_FORMAT_UNKNOWN, // R8G8B8A8_INT + DXGI_FORMAT_UNKNOWN, // R16_INT + DXGI_FORMAT_UNKNOWN, // R16G16_INT + DXGI_FORMAT_UNKNOWN, // R16G16B16A16_INT + DXGI_FORMAT_UNKNOWN, // R32_INT + DXGI_FORMAT_UNKNOWN, // R32G32_INT + DXGI_FORMAT_UNKNOWN, // R32G32B32A32_INT + DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // B8G8R8A8_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // BC1_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // BC2_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // BC3_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // BC7_UNORM_SRGB + DXGI_FORMAT_D16_UNORM, // D16_UNORM + DXGI_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM + DXGI_FORMAT_D32_FLOAT, // D32_FLOAT + DXGI_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM_S8_UINT + DXGI_FORMAT_D32_FLOAT_S8X24_UINT, // D32_FLOAT_S8_UINT + DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_4x4_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_5x4_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_5x5_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_6x5_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_6x6_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_8x5_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_8x6_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_8x8_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_10x5_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_10x6_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_10x8_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_10x10_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT + }; + static_assert(sizeof(JulietToD3D12_DepthFormat) / sizeof(JulietToD3D12_DepthFormat[0]) == ToUnderlying(TextureFormat::Count)); + + // clang-format off + D3D12_INPUT_CLASSIFICATION JulietToD3D12_InputRate[] = + { + D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, // VERTEX + D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA // INSTANCE + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_InputRate) / sizeof(JulietToD3D12_InputRate[0]) == ToUnderlying(VertexInputRate::Count)); + + // clang-format off + D3D12_CULL_MODE JulietToD3D12_CullMode[] = + { + D3D12_CULL_MODE_NONE, + D3D12_CULL_MODE_FRONT, + D3D12_CULL_MODE_BACK + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_CullMode) / sizeof(JulietToD3D12_CullMode[0]) == ToUnderlying(CullMode::Count)); + + // clang-format off + D3D12_FILL_MODE JulietToD3D12_FillMode[] = + { + D3D12_FILL_MODE_SOLID, + D3D12_FILL_MODE_WIREFRAME + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_FillMode) / sizeof(JulietToD3D12_FillMode[0]) == ToUnderlying(FillMode::Count)); + + DXGI_FORMAT JulietToD3D12_VertexFormat[] = { + DXGI_FORMAT_UNKNOWN, // Unknown + DXGI_FORMAT_R32_SINT, // Int + DXGI_FORMAT_R32G32_SINT, // Int2 + DXGI_FORMAT_R32G32B32_SINT, // Int3 + DXGI_FORMAT_R32G32B32A32_SINT, // Int4 + DXGI_FORMAT_R32_UINT, // UInt + DXGI_FORMAT_R32G32_UINT, // UInt2 + DXGI_FORMAT_R32G32B32_UINT, // UInt3 + DXGI_FORMAT_R32G32B32A32_UINT, // UInt4 + DXGI_FORMAT_R32_FLOAT, // Float + DXGI_FORMAT_R32G32_FLOAT, // Float2 + DXGI_FORMAT_R32G32B32_FLOAT, // Float3 + DXGI_FORMAT_R32G32B32A32_FLOAT, // Float4 + DXGI_FORMAT_R8G8_SINT, // Byte2 + DXGI_FORMAT_R8G8B8A8_SINT, // Byte4 + DXGI_FORMAT_R8G8_UINT, // UByte2 + DXGI_FORMAT_R8G8B8A8_UINT, // UByte4 + DXGI_FORMAT_R8G8_SNORM, // Byte2_Norm + DXGI_FORMAT_R8G8B8A8_SNORM, // Byte4_Norm + DXGI_FORMAT_R8G8_UNORM, // UByte2_Norm + DXGI_FORMAT_R8G8B8A8_UNORM, // UByte4_Norm + DXGI_FORMAT_R16G16_SINT, // Short2 + DXGI_FORMAT_R16G16B16A16_SINT, // Short4 + DXGI_FORMAT_R16G16_UINT, // UShort2 + DXGI_FORMAT_R16G16B16A16_UINT, // UShort4 + DXGI_FORMAT_R16G16_SNORM, // Short2_Norm + DXGI_FORMAT_R16G16B16A16_SNORM, // Short4_Norm + DXGI_FORMAT_R16G16_UNORM, // UShort2_Norm + DXGI_FORMAT_R16G16B16A16_UNORM, // UShort4_Norm + DXGI_FORMAT_R16G16_FLOAT, // Half2 + DXGI_FORMAT_R16G16B16A16_FLOAT // Half4 + }; + static_assert(sizeof(JulietToD3D12_VertexFormat) / sizeof(JulietToD3D12_VertexFormat[0]) == + ToUnderlying(VertexElementFormat::Count)); + + // clang-format off + D3D12_PRIMITIVE_TOPOLOGY_TYPE JulietToD3D12_PrimitiveTopologyType[] = { + D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, + D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, + D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE, + D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE, + D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_PrimitiveTopologyType) / sizeof(JulietToD3D12_PrimitiveTopologyType[0]) == + ToUnderlying(PrimitiveType::Count)); + + // clang-format off + D3D12_BLEND JulietToD3D12_BlendFactor[] = + { + D3D12_BLEND_ZERO, + D3D12_BLEND_ZERO, + D3D12_BLEND_ONE, + D3D12_BLEND_SRC_COLOR, + D3D12_BLEND_INV_SRC_COLOR, + D3D12_BLEND_DEST_COLOR, + D3D12_BLEND_INV_DEST_COLOR, + D3D12_BLEND_SRC_ALPHA, + D3D12_BLEND_INV_SRC_ALPHA, + D3D12_BLEND_DEST_ALPHA, + D3D12_BLEND_INV_DEST_ALPHA, + D3D12_BLEND_BLEND_FACTOR, + D3D12_BLEND_INV_BLEND_FACTOR, + D3D12_BLEND_SRC_ALPHA_SAT, + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_BlendFactor) / sizeof(JulietToD3D12_BlendFactor[0]) == ToUnderlying(BlendFactor::Count)); + + // clang-format off + D3D12_BLEND JulietToD3D12_BlendFactorAlpha[] = + { + D3D12_BLEND_ZERO, + D3D12_BLEND_ZERO, + D3D12_BLEND_ONE, + D3D12_BLEND_SRC_ALPHA, + D3D12_BLEND_INV_SRC_ALPHA, + D3D12_BLEND_DEST_ALPHA, + D3D12_BLEND_INV_DEST_ALPHA, + D3D12_BLEND_SRC_ALPHA, + D3D12_BLEND_INV_SRC_ALPHA, + D3D12_BLEND_DEST_ALPHA, + D3D12_BLEND_INV_DEST_ALPHA, + D3D12_BLEND_BLEND_FACTOR, + D3D12_BLEND_INV_BLEND_FACTOR, + D3D12_BLEND_SRC_ALPHA_SAT, + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_BlendFactorAlpha) / sizeof(JulietToD3D12_BlendFactorAlpha[0]) == + ToUnderlying(BlendFactor::Count)); + + // clang-format off + D3D12_BLEND_OP JulietToD3D12_BlendOperation[] = + { + D3D12_BLEND_OP_ADD, + D3D12_BLEND_OP_ADD, + D3D12_BLEND_OP_SUBTRACT, + D3D12_BLEND_OP_REV_SUBTRACT, + D3D12_BLEND_OP_MIN, + D3D12_BLEND_OP_MAX + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_BlendOperation) / sizeof(JulietToD3D12_BlendOperation[0]) == + ToUnderlying(BlendOperation::Count)); + + // clang-format off + D3D12_COMPARISON_FUNC JulietToD3D12_CompareOperation[] = + { + D3D12_COMPARISON_FUNC_NEVER, + D3D12_COMPARISON_FUNC_NEVER, + D3D12_COMPARISON_FUNC_LESS, + D3D12_COMPARISON_FUNC_EQUAL, + D3D12_COMPARISON_FUNC_LESS_EQUAL, + D3D12_COMPARISON_FUNC_GREATER, + D3D12_COMPARISON_FUNC_NOT_EQUAL, + D3D12_COMPARISON_FUNC_GREATER_EQUAL, + D3D12_COMPARISON_FUNC_ALWAYS + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_CompareOperation) / sizeof(JulietToD3D12_CompareOperation[0]) == + ToUnderlying(CompareOperation::Count)); + + // clang-format off + D3D12_STENCIL_OP JulietToD3D12_StencilOperation[] = + { + D3D12_STENCIL_OP_KEEP, + D3D12_STENCIL_OP_KEEP, + D3D12_STENCIL_OP_ZERO, + D3D12_STENCIL_OP_REPLACE, + D3D12_STENCIL_OP_INCR_SAT, + D3D12_STENCIL_OP_DECR_SAT, + D3D12_STENCIL_OP_INVERT, + D3D12_STENCIL_OP_INCR, + D3D12_STENCIL_OP_DECR + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_StencilOperation) / sizeof(JulietToD3D12_StencilOperation[0]) == + ToUnderlying(StencilOperation::Count)); + + // clang-format off +D3D12_PRIMITIVE_TOPOLOGY JulietToD3D12_PrimitiveType[] = +{ + D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, + D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, + D3D_PRIMITIVE_TOPOLOGY_LINELIST, + D3D_PRIMITIVE_TOPOLOGY_LINESTRIP, + D3D_PRIMITIVE_TOPOLOGY_POINTLIST +}; + // clang-format on + static_assert(sizeof(JulietToD3D12_PrimitiveType) / sizeof(JulietToD3D12_PrimitiveType[0]) == ToUnderlying(PrimitiveType::Count)); + + enum class RootParameters : uint8 + { + Constants32Bits, + Count, + }; + + struct D3D12TextureContainer + { + TextureHeader Header; + + D3D12Texture* ActiveTexture; + D3D12Texture** Textures; + uint32 Capacity; + uint32 Count; + + // Note: Swapchain images cannot be cycled + bool CanBeCycled; #if JULIET_DEBUG - char* DebugName; + char* DebugName; #endif - }; + }; - struct D3D12WindowData - { - Window* Window; + struct D3D12WindowData + { + Window* Window; - IDXGISwapChain3* SwapChain; - D3D12TextureContainer SwapChainTextureContainers[GPUDriver::kMaxFramesInFlight]; - DXGI_COLOR_SPACE_TYPE SwapChainColorSpace; - SwapChainComposition SwapChainComposition; - uint8 SwapChainTextureCount; + IDXGISwapChain3* SwapChain; + D3D12TextureContainer SwapChainTextureContainers[GPUDriver::kMaxFramesInFlight]; + DXGI_COLOR_SPACE_TYPE SwapChainColorSpace; + SwapChainComposition SwapChainComposition; + uint8 SwapChainTextureCount; - PresentMode PresentMode; + PresentMode PresentMode; - Fence* InFlightFences[GPUDriver::kMaxFramesInFlight]; + Fence* InFlightFences[GPUDriver::kMaxFramesInFlight]; - uint32 WindowFrameCounter; // Specific to that window. See GraphicsDevice for global counter - uint32 Width; - uint32 Height; - }; + uint32 WindowFrameCounter; // Specific to that window. See GraphicsDevice for global counter + uint32 Width; + uint32 Height; + }; - struct D3D12CommandListBaseData - { - ID3D12CommandAllocator* Allocator; - }; + struct D3D12CommandListBaseData + { + ID3D12CommandAllocator* Allocator; + }; - struct D3D12CopyCommandListData : D3D12CommandListBaseData - { - ID3D12GraphicsCommandList* CommandList; - }; + struct D3D12CopyCommandListData : D3D12CommandListBaseData + { + ID3D12GraphicsCommandList* CommandList; + }; - struct D3D12GraphicsCommandListData : D3D12CommandListBaseData - { - ID3D12GraphicsCommandList6* CommandList; - }; + struct D3D12GraphicsCommandListData : D3D12CommandListBaseData + { + ID3D12GraphicsCommandList6* CommandList; + }; - struct D3D12Shader - { - ByteBuffer ByteCode; + struct D3D12Shader + { + ByteBuffer ByteCode; - uint32 NumSamplers; - uint32 NumUniformBuffers; - uint32 NumStorageBuffers; - uint32 NumStorageTextures; - }; + uint32 NumSamplers; + uint32 NumUniformBuffers; + uint32 NumStorageBuffers; + uint32 NumStorageTextures; + }; - struct D3D12PresentData - { - D3D12WindowData* WindowData; - uint32 SwapChainImageIndex; - }; + struct D3D12PresentData + { + D3D12WindowData* WindowData; + uint32 SwapChainImageIndex; + }; - // https://learn.microsoft.com/en-us/windows/win32/direct3d12/descriptor-heaps - struct D3D12DescriptorHeap - { - D3D12DescriptorHeap* Next; - ID3D12DescriptorHeap* Handle; - D3D12_DESCRIPTOR_HEAP_TYPE HeapType; - D3D12_CPU_DESCRIPTOR_HANDLE DescriptorHeapCPUStart; - D3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeapGPUStart; // only used by GPU heaps - uint32 MaxDescriptors; - uint32 DescriptorSize; - uint32 CurrentDescriptorIndex; // only used by GPU heaps + // https://learn.microsoft.com/en-us/windows/win32/direct3d12/descriptor-heaps + struct D3D12DescriptorHeap + { + D3D12DescriptorHeap* Next; + ID3D12DescriptorHeap* Handle; + D3D12_DESCRIPTOR_HEAP_TYPE HeapType; + D3D12_CPU_DESCRIPTOR_HANDLE DescriptorHeapCPUStart; + D3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeapGPUStart; // only used by GPU heaps + uint32 MaxDescriptors; + uint32 DescriptorSize; + uint32 CurrentDescriptorIndex; // only used by GPU heaps - VectorArena FreeIndices; - index_t CurrentFreeIndex; + VectorArena FreeIndices; + index_t CurrentFreeIndex; - bool Staging : 1; - }; + bool Staging : 1; + }; - struct D3D12Descriptor - { - D3D12DescriptorHeap* Heap; - uint32 Index; - D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle; - D3D12_GPU_DESCRIPTOR_HANDLE GpuHandle; - }; + struct D3D12Descriptor + { + D3D12DescriptorHeap* Heap; + uint32 Index; + D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle; + D3D12_GPU_DESCRIPTOR_HANDLE GpuHandle; + }; - struct D3D12DescriptorHeapPool - { - D3D12DescriptorHeap* FirstFreeDescriptorHeap; - }; + struct D3D12DescriptorHeapPool + { + D3D12DescriptorHeap* FirstFreeDescriptorHeap; + }; - // https://learn.microsoft.com/en-us/windows/win32/direct3d12/descriptors-overview - struct D3D12StagingDescriptor - { - D3D12StagingDescriptorPool* Pool; - D3D12DescriptorHeap* Heap; - D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle; - uint32 CpuHandleIndex; - }; + // https://learn.microsoft.com/en-us/windows/win32/direct3d12/descriptors-overview + struct D3D12StagingDescriptor + { + D3D12StagingDescriptorPool* Pool; + D3D12DescriptorHeap* Heap; + D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle; + uint32 CpuHandleIndex; + }; - struct D3D12StagingDescriptorPool - { - D3D12DescriptorHeap** Heaps; - uint32 HeapCount; + struct D3D12StagingDescriptorPool + { + D3D12DescriptorHeap** Heaps; + uint32 HeapCount; - // Descriptor handles are owned by resources, so these can be thought of as descriptions of a free index within a heap. - uint32 FreeDescriptorCapacity; - uint32 FreeDescriptorCount; - D3D12StagingDescriptor* FreeDescriptors; - }; + // Descriptor handles are owned by resources, so these can be thought of as descriptions of a free index within a heap. + uint32 FreeDescriptorCapacity; + uint32 FreeDescriptorCount; + D3D12StagingDescriptor* FreeDescriptors; + }; - struct D3D12Buffer - { - // Note: This three variables need to stay at the top and in this order - D3D12Descriptor Descriptor; - ID3D12Resource* Handle; - D3D12_RESOURCE_STATES CurrentState; + struct D3D12Buffer + { + // Note: This three variables need to stay at the top and in this order + D3D12Descriptor Descriptor; + ID3D12Resource* Handle; + D3D12_RESOURCE_STATES CurrentState; - // Anything here can be any order - D3D12Buffer* Next; - size_t Size; - }; + // Anything here can be any order + D3D12Buffer* Next; + size_t Size; + }; - struct D3D12Driver : GPUDriver - { - GraphicsDevice* GraphicsDevice; + struct D3D12Driver : GPUDriver + { + GraphicsDevice* GraphicsDevice; - // D3D12 - DynamicLibrary* D3D12DLL; - ID3D12Device5* D3D12Device; - PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE D3D12SerializeVersionedRootSignatureFct; - ID3D12CommandQueue* GraphicsQueue; - D3D12_COMMAND_QUEUE_DESC QueueDesc[ToUnderlying(QueueType::Count)]; + // D3D12 + DynamicLibrary* D3D12DLL; + ID3D12Device5* D3D12Device; + PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE D3D12SerializeVersionedRootSignatureFct; + ID3D12CommandQueue* GraphicsQueue; + D3D12_COMMAND_QUEUE_DESC QueueDesc[ToUnderlying(QueueType::Count)]; #if JULIET_DEBUG - ID3D12Debug1* D3D12Debug; + ID3D12Debug1* D3D12Debug; #endif - // Indirect commands signature - ID3D12CommandSignature* IndirectDrawCommandSignature; - ID3D12CommandSignature* IndirectIndexedDrawCommandSignature; - ID3D12CommandSignature* IndirectDispatchCommandSignature; + // Indirect commands signature + ID3D12CommandSignature* IndirectDrawCommandSignature; + ID3D12CommandSignature* IndirectIndexedDrawCommandSignature; + ID3D12CommandSignature* IndirectDispatchCommandSignature; - // DXGI - IDXGIFactory4* DXGIFactory; - IDXGIAdapter1* DXGIAdapter; + // DXGI + IDXGIFactory4* DXGIFactory; + IDXGIAdapter1* DXGIAdapter; #if JULIET_DEBUG - DynamicLibrary* DXGIDebugDLL; - IDXGIDebug* DXGIDebug; + DynamicLibrary* DXGIDebugDLL; + IDXGIDebug* DXGIDebug; #ifdef IDXGIINFOQUEUE_SUPPORTED - IDXGIInfoQueue* DXGIInfoQueue; + IDXGIInfoQueue* DXGIInfoQueue; #endif #endif - // Windows - // TODO: Support more than one window - D3D12WindowData* WindowData; + // Windows + // TODO: Support more than one window + D3D12WindowData* WindowData; - // Resources - D3D12CommandList** AvailableCommandLists; - uint8 AvailableCommandListCapacity; - uint8 AvailableCommandListCount; + // Resources + D3D12CommandList** AvailableCommandLists; + uint8 AvailableCommandListCapacity; + uint8 AvailableCommandListCount; - D3D12CommandList** SubmittedCommandLists; - uint8 SubmittedCommandListCapacity; - uint8 SubmittedCommandListCount; + D3D12CommandList** SubmittedCommandLists; + uint8 SubmittedCommandListCapacity; + uint8 SubmittedCommandListCount; - D3D12Fence** AvailableFences; - uint32 AvailableFenceCount; - uint32 AvailableFenceCapacity; + D3D12Fence** AvailableFences; + uint32 AvailableFenceCount; + uint32 AvailableFenceCapacity; - D3D12GraphicsPipeline** GraphicsPipelinesToDispose; - uint32 GraphicsPipelinesToDisposeCount; - uint32 GraphicsPipelinesToDisposeCapacity; + D3D12GraphicsPipeline** GraphicsPipelinesToDispose; + uint32 GraphicsPipelinesToDisposeCount; + uint32 GraphicsPipelinesToDisposeCapacity; - D3D12GraphicsRootSignature* BindlessRootSignature; + D3D12GraphicsRootSignature* BindlessRootSignature; - D3D12StagingDescriptorPool* StagingDescriptorPools[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES]; - D3D12DescriptorHeap* BindlessDescriptorHeap; - D3D12DescriptorHeapPool SamplerHeapPool; + D3D12StagingDescriptorPool* StagingDescriptorPools[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES]; + D3D12DescriptorHeap* BindlessDescriptorHeap; + D3D12DescriptorHeapPool SamplerHeapPool; - String Semantic; + String Semantic; - uint8 FramesInFlight; - uint64 FrameCounter = 0; // Number of frame since inception + uint8 FramesInFlight; + uint64 FrameCounter = 0; // Number of frame since inception - bool IsTearingSupported : 1; - bool IsUMAAvailable : 1; - bool IsUMACacheCoherent : 1; - bool GPUUploadHeapSupported : 1; - }; + bool IsTearingSupported : 1; + bool IsUMAAvailable : 1; + bool IsUMACacheCoherent : 1; + bool GPUUploadHeapSupported : 1; + }; - struct D3D12GraphicsRootSignature - { - ID3D12RootSignature* Handle; - }; + struct D3D12GraphicsRootSignature + { + ID3D12RootSignature* Handle; + }; - struct D3D12GraphicsPipeline - { + struct D3D12GraphicsPipeline + { #if ALLOW_SHADER_HOT_RELOAD - // Template to recreate an ID3D12PipelineState when shader are hot reloaded - // Stripped out in shipping build as the struct is huge - D3D12_GRAPHICS_PIPELINE_STATE_DESC PSODescTemplate; + // Template to recreate an ID3D12PipelineState when shader are hot reloaded + // Stripped out in shipping build as the struct is huge + D3D12_GRAPHICS_PIPELINE_STATE_DESC PSODescTemplate; - // Keeping shaders byte code to make it easier to recreate the ID3D12PipelineState - // Those will be freed when the pipeline is destroyed or updated - D3D12Shader* VertexShaderCache; - D3D12Shader* FragmentShaderCache; + // Keeping shaders byte code to make it easier to recreate the ID3D12PipelineState + // Those will be freed when the pipeline is destroyed or updated + D3D12Shader* VertexShaderCache; + D3D12Shader* FragmentShaderCache; #endif - ID3D12PipelineState* PipelineState; - D3D12GraphicsRootSignature* RootSignature; - PrimitiveType PrimitiveType; + ID3D12PipelineState* PipelineState; + D3D12GraphicsRootSignature* RootSignature; + PrimitiveType PrimitiveType; - uint32 VertexStrides[GPUDriver::kMaxVertexBuffers]; + uint32 VertexStrides[GPUDriver::kMaxVertexBuffers]; - uint32 VertexSamplerCount; - uint32 VertexUniformBufferCount; - uint32 VertexStorageBufferCount; - uint32 VertexStorageTextureCount; + uint32 VertexSamplerCount; + uint32 VertexUniformBufferCount; + uint32 VertexStorageBufferCount; + uint32 VertexStorageTextureCount; - uint32 FragmentSamplerCount; - uint32 FragmentUniformBufferCount; - uint32 FragmentStorageBufferCount; - uint32 FragmentStorageTextureCount; + uint32 FragmentSamplerCount; + uint32 FragmentUniformBufferCount; + uint32 FragmentStorageBufferCount; + uint32 FragmentStorageTextureCount; - int ReferenceCount; - }; + int ReferenceCount; + }; - struct D3D12CommandList - { - CommandListHeader Common; + struct D3D12CommandList + { + CommandListHeader Common; - index_t ID; + index_t ID; - D3D12Driver* Driver; + D3D12Driver* Driver; - D3D12PresentData* PresentDatas; - uint32 PresentDataCapacity; - uint32 PresentDataCount; + D3D12PresentData* PresentDatas; + uint32 PresentDataCapacity; + uint32 PresentDataCount; - D3D12Fence* InFlightFence; - bool AutoReleaseFence; + D3D12Fence* InFlightFence; + bool AutoReleaseFence; - D3D12GraphicsCommandListData GraphicsCommandList; - D3D12GraphicsCommandListData ComputeCommandList; - D3D12CopyCommandListData CopyCommandList; + D3D12GraphicsCommandListData GraphicsCommandList; + D3D12GraphicsCommandListData ComputeCommandList; + D3D12CopyCommandListData CopyCommandList; - D3D12GraphicsPipeline* CurrentGraphicsPipeline; + D3D12GraphicsPipeline* CurrentGraphicsPipeline; - D3D12TextureSubresource* ColorTargetSubresources[GPUDriver::kMaxColorTargetInfo]; - D3D12TextureSubresource* ColorResolveSubresources[GPUDriver::kMaxColorTargetInfo]; - D3D12TextureSubresource* DepthStencilSubresource; + D3D12TextureSubresource* ColorTargetSubresources[GPUDriver::kMaxColorTargetInfo]; + D3D12TextureSubresource* ColorResolveSubresources[GPUDriver::kMaxColorTargetInfo]; + D3D12TextureSubresource* DepthStencilSubresource; - bool NeedVertexBufferBind : 1; - bool NeedVertexSamplerBind : 1; - bool NeedVertexStorageTextureBind : 1; - bool NeedVertexStorageBufferBind : 1; + bool NeedVertexBufferBind : 1; + bool NeedVertexSamplerBind : 1; + bool NeedVertexStorageTextureBind : 1; + bool NeedVertexStorageBufferBind : 1; - bool NeedFragmentSamplerBind : 1; - bool NeedFragmentStorageTextureBind : 1; - bool NeedFragmentStorageBufferBind : 1; + bool NeedFragmentSamplerBind : 1; + bool NeedFragmentStorageTextureBind : 1; + bool NeedFragmentStorageBufferBind : 1; - bool NeedVertexUniformBufferBind[GPUDriver::kMaxUniformBuffersPerStage]; - bool NeedFragmentUniformBufferBind[GPUDriver::kMaxUniformBuffersPerStage]; + bool NeedVertexUniformBufferBind[GPUDriver::kMaxUniformBuffersPerStage]; + bool NeedFragmentUniformBufferBind[GPUDriver::kMaxUniformBuffersPerStage]; - // D3D12UniformBuffer *vertexUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage]; - // D3D12UniformBuffer *fragmentUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage]; + // D3D12UniformBuffer *vertexUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage]; + // D3D12UniformBuffer *fragmentUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage]; - D3D12DescriptorHeap* CRB_SRV_UAV_Heap; - D3D12DescriptorHeap* Sampler_Heap; + D3D12DescriptorHeap* CRB_SRV_UAV_Heap; + D3D12DescriptorHeap* Sampler_Heap; - // Resource Tracking - D3D12Texture** UsedTextures; - uint32 UsedTextureCount; - uint32 UsedTextureCapacity; + // Resource Tracking + D3D12Texture** UsedTextures; + uint32 UsedTextureCount; + uint32 UsedTextureCapacity; - D3D12GraphicsPipeline** UsedGraphicsPipelines; - uint32 UsedGraphicsPipelineCount; - uint32 UsedGraphicsPipelineCapacity; - }; + D3D12GraphicsPipeline** UsedGraphicsPipelines; + uint32 UsedGraphicsPipelineCount; + uint32 UsedGraphicsPipelineCapacity; + }; - // D3D12 subresourcces: https://learn.microsoft.com/en-us/windows/win32/direct3d12/subresources (mipmaps, etc..) - struct D3D12TextureSubresource - { - D3D12Texture* Parent; - uint32 Layer; - uint32 Level; - uint32 Depth; - uint32 Index; + // D3D12 subresourcces: https://learn.microsoft.com/en-us/windows/win32/direct3d12/subresources (mipmaps, etc..) + struct D3D12TextureSubresource + { + D3D12Texture* Parent; + uint32 Layer; + uint32 Level; + uint32 Depth; + uint32 Index; - // One per depth slice - D3D12StagingDescriptor* RTVHandles; // NULL if not a color target + // One per depth slice + D3D12StagingDescriptor* RTVHandles; // NULL if not a color target - D3D12StagingDescriptor UAVHandle; // NULL if not a compute storage write texture - D3D12StagingDescriptor DSVHandle; // NULL if not a depth stencil target - }; + D3D12StagingDescriptor UAVHandle; // NULL if not a compute storage write texture + D3D12StagingDescriptor DSVHandle; // NULL if not a depth stencil target + }; - struct D3D12Texture - { - D3D12TextureContainer* Container; - uint32 IndexInContainer; + struct D3D12Texture + { + D3D12TextureContainer* Container; + uint32 IndexInContainer; - ID3D12Resource* Resource; + ID3D12Resource* Resource; - D3D12TextureSubresource* Subresources; - uint32 SubresourceCount; // Layer Count * number of Levels + D3D12TextureSubresource* Subresources; + uint32 SubresourceCount; // Layer Count * number of Levels - D3D12StagingDescriptor SRVHandle; + D3D12StagingDescriptor SRVHandle; - // TODO: Should be atomic to support multithreading - int32 ReferenceCount; - }; + // TODO: Should be atomic to support multithreading + int32 ReferenceCount; + }; - struct D3D12Fence - { - ID3D12Fence* Handle; - HANDLE Event; // used for blocking - int32 ReferenceCount; // TODO : Atomic - }; + struct D3D12Fence + { + ID3D12Fence* Handle; + HANDLE Event; // used for blocking + int32 ReferenceCount; // TODO : Atomic + }; - // -------------- - // End Data Types + // -------------- + // End Data Types - // ------------- + // ------------- - DXGI_FORMAT ConvertToD3D12TextureFormat(TextureFormat format) - { - return JulietToD3D12_TextureFormat[ToUnderlying(format)]; - } + DXGI_FORMAT ConvertToD3D12TextureFormat(TextureFormat format) + { + return JulietToD3D12_TextureFormat[ToUnderlying(format)]; + } - DXGI_FORMAT ConvertToD3D12DepthFormat(TextureFormat format) - { - return JulietToD3D12_DepthFormat[ToUnderlying(format)]; - } + DXGI_FORMAT ConvertToD3D12DepthFormat(TextureFormat format) + { + return JulietToD3D12_DepthFormat[ToUnderlying(format)]; + } - // From SDLGPU - // TODO Do my own version. - void D3D12_LogError(NonNullPtr D3D12Device, const char* errorMessage, HRESULT result) - { + // From SDLGPU + // TODO Do my own version. + void D3D12_LogError(NonNullPtr D3D12Device, const char* errorMessage, HRESULT result) + { #define MAX_ERROR_LEN 1024 // FIXME: Arbitrary! - // Buffer for text, ensure space for \0 terminator after buffer - char wszMsgBuff[MAX_ERROR_LEN + 1]; - // Number of chars returned. + // Buffer for text, ensure space for \0 terminator after buffer + char wszMsgBuff[MAX_ERROR_LEN + 1]; + // Number of chars returned. - if (result == DXGI_ERROR_DEVICE_REMOVED) - { - result = D3D12Device->GetDeviceRemovedReason(); - } - - // Try to get the message from the system errors. - DWORD dwChars = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, - static_cast(result), 0, wszMsgBuff, MAX_ERROR_LEN, nullptr); - - // No message? Screw it, just post the code. - if (dwChars == 0) - { - Log(LogLevel::Error, LogCategory::Graphics, "%s! Error: " HRESULT_FMT, errorMessage, result); - return; - } - - // Ensure valid range - dwChars = Min(dwChars, MAX_ERROR_LEN); - - // Trim whitespace from tail of message - while (dwChars > 0) - { - if (wszMsgBuff[dwChars - 1] <= ' ') - { - dwChars--; - } - else - { - break; - } - } - - // Ensure null-terminated string - wszMsgBuff[dwChars] = '\0'; - - Log(LogLevel::Error, LogCategory::Graphics, "%s! Error: %s" HRESULT_FMT, errorMessage, wszMsgBuff, result); + if (result == DXGI_ERROR_DEVICE_REMOVED) + { + result = D3D12Device->GetDeviceRemovedReason(); } + // Try to get the message from the system errors. + DWORD dwChars = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, + static_cast(result), 0, wszMsgBuff, MAX_ERROR_LEN, nullptr); + + // No message? Screw it, just post the code. + if (dwChars == 0) + { + Log(LogLevel::Error, LogCategory::Graphics, "%s! Error: " HRESULT_FMT, errorMessage, result); + return; + } + + // Ensure valid range + dwChars = Min(dwChars, MAX_ERROR_LEN); + + // Trim whitespace from tail of message + while (dwChars > 0) + { + if (wszMsgBuff[dwChars - 1] <= ' ') + { + dwChars--; + } + else + { + break; + } + } + + // Ensure null-terminated string + wszMsgBuff[dwChars] = '\0'; + + Log(LogLevel::Error, LogCategory::Graphics, "%s! Error: %s" HRESULT_FMT, errorMessage, wszMsgBuff, result); + } + #if JULIET_DEBUG - String GetDescriptorTypeNane(D3D12_DESCRIPTOR_HEAP_TYPE type) + String GetDescriptorTypeNane(D3D12_DESCRIPTOR_HEAP_TYPE type) + { + switch (type) { - switch (type) - { - case D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV"); - case D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER"); - case D3D12_DESCRIPTOR_HEAP_TYPE_RTV: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_RTV"); - case D3D12_DESCRIPTOR_HEAP_TYPE_DSV: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_DSV"); - case D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES: return WrapString("Invalid"); - } - return WrapString("Invalid"); + case D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV"); + case D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER"); + case D3D12_DESCRIPTOR_HEAP_TYPE_RTV: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_RTV"); + case D3D12_DESCRIPTOR_HEAP_TYPE_DSV: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_DSV"); + case D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES: return WrapString("Invalid"); } + return WrapString("Invalid"); + } #endif - bool CheckResourceTypeTier(ID3D12Device5* device) + bool CheckResourceTypeTier(ID3D12Device5* device) + { + D3D12_FEATURE_DATA_D3D12_OPTIONS options = {}; + HRESULT result = + device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS)); + if (SUCCEEDED(result)) { - D3D12_FEATURE_DATA_D3D12_OPTIONS options = {}; - HRESULT result = - device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS)); - if (SUCCEEDED(result)) + if (options.ResourceBindingTier < D3D12_RESOURCE_BINDING_TIER_3) { - if (options.ResourceBindingTier < D3D12_RESOURCE_BINDING_TIER_3) - { - Juliet::LogError(LogCategory::Graphics, "Resource Binding Tier 3 not supported. :("); - return false; - } - return true; - } - - Juliet::LogError(LogCategory::Graphics, "Couldn't fetch D3D12_FEATURE_D3D12_OPTIONS :("); - return false; - } - - bool CheckShaderModel(ID3D12Device5* device) - { - // Check Shader Model - bool foundShaderModel = false; - D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {}; - constexpr D3D_SHADER_MODEL allModelVersions[] = { -#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 612) - D3D_SHADER_MODEL_6_9, -#endif -#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606) - D3D_SHADER_MODEL_6_8, -#endif -#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 3) - D3D_SHADER_MODEL_6_7, -#endif - D3D_SHADER_MODEL_6_6, D3D_SHADER_MODEL_6_5, D3D_SHADER_MODEL_6_4, D3D_SHADER_MODEL_6_3, - D3D_SHADER_MODEL_6_2, D3D_SHADER_MODEL_6_1, D3D_SHADER_MODEL_6_0, D3D_SHADER_MODEL_5_1 - }; - for (auto allModelVersion : allModelVersions) - { - shaderModel.HighestShaderModel = allModelVersion; - HRESULT result = device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &shaderModel, - sizeof(D3D12_FEATURE_DATA_SHADER_MODEL)); - if (result != E_INVALIDARG) - { - if (FAILED(result)) - { - shaderModel.HighestShaderModel = static_cast(0); - } - else - { - foundShaderModel = true; - break; - } - } - } - - if (!foundShaderModel) - { - shaderModel.HighestShaderModel = static_cast(0); - } - - if (shaderModel.HighestShaderModel < D3D_SHADER_MODEL_6_6) - { - Juliet::LogError(LogCategory::Graphics, "Shader Model 6.6 not supported. :("); + LogError(LogCategory::Graphics, "Resource Binding Tier 3 not supported. :("); return false; } return true; } - bool D3D12_CheckDriver() + LogError(LogCategory::Graphics, "Couldn't fetch D3D12_FEATURE_D3D12_OPTIONS :("); + return false; + } + + bool CheckShaderModel(ID3D12Device5* device) + { + // Check Shader Model + bool foundShaderModel = false; + D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {}; + constexpr D3D_SHADER_MODEL allModelVersions[] = { +#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 612) + D3D_SHADER_MODEL_6_9, +#endif +#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606) + D3D_SHADER_MODEL_6_8, +#endif +#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 3) + D3D_SHADER_MODEL_6_7, +#endif + D3D_SHADER_MODEL_6_6, D3D_SHADER_MODEL_6_5, D3D_SHADER_MODEL_6_4, D3D_SHADER_MODEL_6_3, + D3D_SHADER_MODEL_6_2, D3D_SHADER_MODEL_6_1, D3D_SHADER_MODEL_6_0, D3D_SHADER_MODEL_5_1 + }; + for (auto allModelVersion : allModelVersions) { - // Can we Load D3D12.dll and the create device function - DynamicLibrary* d3d12_dll = LoadDynamicLibrary(D3D12_DLL); - if (d3d12_dll == nullptr) + shaderModel.HighestShaderModel = allModelVersion; + HRESULT result = device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &shaderModel, + sizeof(D3D12_FEATURE_DATA_SHADER_MODEL)); + if (result != E_INVALIDARG) { - Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Couldn't find " D3D12_DLL); - return false; + if (FAILED(result)) + { + shaderModel.HighestShaderModel = static_cast(0); + } + else + { + foundShaderModel = true; + break; + } } + } - auto* D3D12CreateDeviceFuncPtr = - TOD3D12FuncPtr(PFN_D3D12_CREATE_DEVICE, LoadFunction(d3d12_dll, D3D12_CREATEDEVICE_FUNC)); - if (D3D12CreateDeviceFuncPtr == nullptr) - { - Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Couldn't find function " D3D12_CREATEDEVICE_FUNC " in " D3D12_DLL); - UnloadDynamicLibrary(d3d12_dll); - return false; - } + if (!foundShaderModel) + { + shaderModel.HighestShaderModel = static_cast(0); + } - // Can create DXGI factory ? - IDXGIFactory1* factory1 = nullptr; - HRESULT result = CreateDXGIFactory1(IID_IDXGIFactory1, reinterpret_cast(&factory1)); - if (FAILED(result)) - { - Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Cannot create DXGIFactory1"); - return false; - } + if (shaderModel.HighestShaderModel < D3D_SHADER_MODEL_6_6) + { + LogError(LogCategory::Graphics, "Shader Model 6.6 not supported. :("); + return false; + } + return true; + } - // Can query the 1.4 factory ? - IDXGIFactory4* factory4 = nullptr; - result = factory1->QueryInterface(IID_IDXGIFactory4, reinterpret_cast(&factory4)); - if (FAILED(result)) - { - factory1->Release(); - Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Failed to query DXGI1.4."); - return false; - } - factory4->Release(); + bool D3D12_CheckDriver() + { + // Can we Load D3D12.dll and the create device function + DynamicLibrary* d3d12_dll = LoadDynamicLibrary(D3D12_DLL); + if (d3d12_dll == nullptr) + { + Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Couldn't find " D3D12_DLL); + return false; + } - // Check for 1.6. (It's not mandatory). - IDXGIAdapter1* adapter = nullptr; - IDXGIFactory6* factory6 = nullptr; - result = factory1->QueryInterface(IID_IDXGIFactory6, reinterpret_cast(&factory6)); - if (SUCCEEDED(result)) - { - result = factory6->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, - IID_IDXGIAdapter1, reinterpret_cast(&adapter)); - factory6->Release(); - } - else - { - result = factory1->EnumAdapters1(0, &adapter); - } + auto* D3D12CreateDeviceFuncPtr = + TOD3D12FuncPtr(PFN_D3D12_CREATE_DEVICE, LoadFunction(d3d12_dll, D3D12_CREATEDEVICE_FUNC)); + if (D3D12CreateDeviceFuncPtr == nullptr) + { + Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Couldn't find function " D3D12_CREATEDEVICE_FUNC " in " D3D12_DLL); + UnloadDynamicLibrary(d3d12_dll); + return false; + } - if (FAILED(result)) - { - Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Failed to find an adapter for D3D12."); + // Can create DXGI factory ? + IDXGIFactory1* factory1 = nullptr; + HRESULT result = CreateDXGIFactory1(IID_IDXGIFactory1, reinterpret_cast(&factory1)); + if (FAILED(result)) + { + Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Cannot create DXGIFactory1"); + return false; + } - factory1->Release(); - return false; - } - - ID3D12Device5* device = nullptr; - result = D3D12CreateDeviceFuncPtr(static_cast(adapter), kD3DFeatureLevel, IID_ID3D12Device5, - reinterpret_cast(&device)); - - bool driverIsValid = true; - if (SUCCEEDED(result)) - { - driverIsValid &= CheckShaderModel(device); - driverIsValid &= CheckResourceTypeTier(device); - - device->Release(); - } - else - { - Log(LogLevel::Warning, LogCategory::Graphics, - "DX12: Failed to create a D3D12Device with feature level %s.", kD3DFeatureLevelStr); - driverIsValid = false; - } - adapter->Release(); + // Can query the 1.4 factory ? + IDXGIFactory4* factory4 = nullptr; + result = factory1->QueryInterface(IID_IDXGIFactory4, reinterpret_cast(&factory4)); + if (FAILED(result)) + { factory1->Release(); - - return driverIsValid; + Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Failed to query DXGI1.4."); + return false; } + factory4->Release(); - void DestroyGraphicsRootSignature(D3D12GraphicsRootSignature* rootSignature) + // Check for 1.6. (It's not mandatory). + IDXGIAdapter1* adapter = nullptr; + IDXGIFactory6* factory6 = nullptr; + result = factory1->QueryInterface(IID_IDXGIFactory6, reinterpret_cast(&factory6)); + if (SUCCEEDED(result)) { - if (!rootSignature) - { - return; - } - if (rootSignature->Handle) - { - rootSignature->Handle->Release(); - } - Free(rootSignature); + result = factory6->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, IID_IDXGIAdapter1, + reinterpret_cast(&adapter)); + factory6->Release(); } - - D3D12GraphicsRootSignature* CreateGraphicsRootSignature(NonNullPtr d3d12Driver) + else { - auto d3d12GraphicsRootSignature = - static_cast(Calloc(1, sizeof(D3D12GraphicsRootSignature))); - if (!d3d12GraphicsRootSignature) - { - return nullptr; - } - - D3D12_ROOT_PARAMETER1 parameters[ToUnderlying(RootParameters::Count)] = {}; - parameters[ToUnderlying(RootParameters::Constants32Bits)] = { - .ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS, - .Constants = { - .ShaderRegister = 0, - .RegisterSpace = 0, - .Num32BitValues = 58, // 58 because each root cbv takes 2 uints, and the max is 64 - }, - .ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL - }; - - D3D12_STATIC_SAMPLER_DESC samplers[] = { - { - // s_nearest - .Filter = D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR, - .AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP, - .AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP, - .AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP, - .MipLODBias = 0.0f, - .MaxAnisotropy = 0, - .ComparisonFunc = D3D12_COMPARISON_FUNC_NONE, - .BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK, - .MinLOD = 0.0f, - .MaxLOD = D3D12_FLOAT32_MAX, - .ShaderRegister = 0, - .RegisterSpace = 0, - .ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL, - }, - }; - - D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc = { - .Version = D3D_ROOT_SIGNATURE_VERSION_1_1, - .Desc_1_1 = { - .NumParameters = ArraySize(parameters), - .pParameters = parameters, - .NumStaticSamplers = ArraySize(samplers), - .pStaticSamplers = samplers, - .Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | - D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED | - D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED, - }, - }; - - // Serialize the root signature - ID3DBlob* serializedRootSignature; - ID3DBlob* errorBlob; - HRESULT res = - d3d12Driver->D3D12SerializeVersionedRootSignatureFct(&rootSignatureDesc, &serializedRootSignature, &errorBlob); - if (FAILED(res)) - { - if (errorBlob) - { - auto errorBuffer = errorBlob->GetBufferPointer(); - Juliet::LogError(LogCategory::Graphics, "Failed to serialize RootSignature: %s", errorBuffer); - - errorBlob->Release(); - } - DestroyGraphicsRootSignature(d3d12GraphicsRootSignature); - return nullptr; - } - - // Create the root signature - ID3D12RootSignature* rootSignature; - res = d3d12Driver->D3D12Device->CreateRootSignature(0, serializedRootSignature->GetBufferPointer(), - serializedRootSignature->GetBufferSize(), IID_ID3D12RootSignature, - reinterpret_cast(&rootSignature)); - if (FAILED(res)) - { - if (errorBlob) - { - Juliet::LogError(LogCategory::Graphics, "Failed to create RootSignature: %s", - (const char*)errorBlob->GetBufferPointer()); - errorBlob->Release(); - } - DestroyGraphicsRootSignature(d3d12GraphicsRootSignature); - return nullptr; - } - - d3d12GraphicsRootSignature->Handle = rootSignature; - return d3d12GraphicsRootSignature; + result = factory1->EnumAdapters1(0, &adapter); } + + if (FAILED(result)) + { + Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Failed to find an adapter for D3D12."); + + factory1->Release(); + return false; + } + + ID3D12Device5* device = nullptr; + result = D3D12CreateDeviceFuncPtr(static_cast(adapter), kD3DFeatureLevel, IID_ID3D12Device5, + reinterpret_cast(&device)); + + bool driverIsValid = true; + if (SUCCEEDED(result)) + { + driverIsValid &= CheckShaderModel(device); + driverIsValid &= CheckResourceTypeTier(device); + + device->Release(); + } + else + { + Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Failed to create a D3D12Device with feature level %s.", + kD3DFeatureLevelStr); + driverIsValid = false; + } + adapter->Release(); + factory1->Release(); + + return driverIsValid; + } + + void DestroyGraphicsRootSignature(D3D12GraphicsRootSignature* rootSignature) + { + if (!rootSignature) + { + return; + } + if (rootSignature->Handle) + { + rootSignature->Handle->Release(); + } + Free(rootSignature); + } + + D3D12GraphicsRootSignature* CreateGraphicsRootSignature(NonNullPtr d3d12Driver) + { + auto d3d12GraphicsRootSignature = + static_cast(Calloc(1, sizeof(D3D12GraphicsRootSignature))); + if (!d3d12GraphicsRootSignature) + { + return nullptr; + } + + D3D12_ROOT_PARAMETER1 parameters[ToUnderlying(RootParameters::Count)] = {}; + parameters[ToUnderlying(RootParameters::Constants32Bits)] = { + .ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS, + .Constants = { + .ShaderRegister = 0, + .RegisterSpace = 0, + .Num32BitValues = 58, // 58 because each root cbv takes 2 uints, and the max is 64 + }, + .ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL + }; + + D3D12_STATIC_SAMPLER_DESC samplers[] = { + { + // s_nearest + .Filter = D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR, + .AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP, + .AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP, + .AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP, + .MipLODBias = 0.0f, + .MaxAnisotropy = 0, + .ComparisonFunc = D3D12_COMPARISON_FUNC_NONE, + .BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK, + .MinLOD = 0.0f, + .MaxLOD = D3D12_FLOAT32_MAX, + .ShaderRegister = 0, + .RegisterSpace = 0, + .ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL, + }, + }; + + D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc = { + .Version = D3D_ROOT_SIGNATURE_VERSION_1_1, + .Desc_1_1 = { + .NumParameters = ArraySize(parameters), + .pParameters = parameters, + .NumStaticSamplers = ArraySize(samplers), + .pStaticSamplers = samplers, + .Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | + D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED | + D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED, + }, + }; + + // Serialize the root signature + ID3DBlob* serializedRootSignature; + ID3DBlob* errorBlob; + HRESULT res = d3d12Driver->D3D12SerializeVersionedRootSignatureFct(&rootSignatureDesc, &serializedRootSignature, &errorBlob); + if (FAILED(res)) + { + if (errorBlob) + { + auto errorBuffer = errorBlob->GetBufferPointer(); + LogError(LogCategory::Graphics, "Failed to serialize RootSignature: %s", errorBuffer); + + errorBlob->Release(); + } + DestroyGraphicsRootSignature(d3d12GraphicsRootSignature); + return nullptr; + } + + // Create the root signature + ID3D12RootSignature* rootSignature; + res = d3d12Driver->D3D12Device->CreateRootSignature(0, serializedRootSignature->GetBufferPointer(), + serializedRootSignature->GetBufferSize(), IID_ID3D12RootSignature, + reinterpret_cast(&rootSignature)); + if (FAILED(res)) + { + if (errorBlob) + { + LogError(LogCategory::Graphics, "Failed to create RootSignature: %s", (const char*)errorBlob->GetBufferPointer()); + errorBlob->Release(); + } + DestroyGraphicsRootSignature(d3d12GraphicsRootSignature); + return nullptr; + } + + d3d12GraphicsRootSignature->Handle = rootSignature; + return d3d12GraphicsRootSignature; + } #if JULIET_DEBUG #ifdef IDXGIINFOQUEUE_SUPPORTED @@ -1166,2498 +1160,2481 @@ namespace Juliet #define DXGIDEBUG_DLL "dxgidebug.dll" #define DXGI_GET_DEBUG_INTERFACE_FUNC "DXGIGetDebugInterface" - void InitializeDXGIDebug(NonNullPtr driver) + void InitializeDXGIDebug(NonNullPtr driver) + { + // See https://github.com/microsoft/DirectX-Graphics-Samples/blob/7aa24663f26e547a5bc437db028dfcfdb4b3c8f3/TechniqueDemos/D3D12MemoryManagement/src/Framework.cpp#L957 + // For win10 only we can just use dxgiGetDebugInterface1 + using LPDXGIGETDEBUGINTERFACE = HRESULT(WINAPI*)(REFIID, void**); + + driver->DXGIDebugDLL = LoadDynamicLibrary(DXGIDEBUG_DLL); + if (driver->DXGIDebugDLL) { - // See https://github.com/microsoft/DirectX-Graphics-Samples/blob/7aa24663f26e547a5bc437db028dfcfdb4b3c8f3/TechniqueDemos/D3D12MemoryManagement/src/Framework.cpp#L957 - // For win10 only we can just use dxgiGetDebugInterface1 - using LPDXGIGETDEBUGINTERFACE = HRESULT(WINAPI*)(REFIID, void**); + auto dxgiGetDebugInterface = + TOD3D12FuncPtr(LPDXGIGETDEBUGINTERFACE, LoadFunction(driver->DXGIDebugDLL, DXGI_GET_DEBUG_INTERFACE_FUNC)); - driver->DXGIDebugDLL = LoadDynamicLibrary(DXGIDEBUG_DLL); - if (driver->DXGIDebugDLL) + HRESULT result = dxgiGetDebugInterface(IID_IDXGIDebug, (void**)&driver->DXGIDebug); + if (FAILED(result)) { - auto dxgiGetDebugInterface = - TOD3D12FuncPtr(LPDXGIGETDEBUGINTERFACE, LoadFunction(driver->DXGIDebugDLL, DXGI_GET_DEBUG_INTERFACE_FUNC)); + Log(LogLevel::Warning, LogCategory::Graphics, "Could not get IDXGIDebug interface"); + } - HRESULT result = dxgiGetDebugInterface(IID_IDXGIDebug, (void**)&driver->DXGIDebug); - if (FAILED(result)) - { - Log(LogLevel::Warning, LogCategory::Graphics, "Could not get IDXGIDebug interface"); - } - - result = dxgiGetDebugInterface(IID_IDXGIInfoQueue, (void**)&driver->DXGIInfoQueue); - if (FAILED(result)) - { - Log(LogLevel::Warning, LogCategory::Graphics, "Could not get IDXGIInfoQueue interface"); - } - else - { - driver->DXGIInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, TRUE); - driver->DXGIInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, TRUE); - driver->DXGIInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_WARNING, TRUE); - } + result = dxgiGetDebugInterface(IID_IDXGIInfoQueue, (void**)&driver->DXGIInfoQueue); + if (FAILED(result)) + { + Log(LogLevel::Warning, LogCategory::Graphics, "Could not get IDXGIInfoQueue interface"); + } + else + { + driver->DXGIInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, TRUE); + driver->DXGIInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, TRUE); + driver->DXGIInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_WARNING, TRUE); } } + } - void ShutdownDXGIDebug(NonNullPtr driver) + void ShutdownDXGIDebug(NonNullPtr driver) + { + if (driver->DXGIDebug) { - if (driver->DXGIDebug) - { - driver->DXGIDebug->ReportLiveObjects(DXGI_DEBUG_ALL, static_cast( - DXGI_DEBUG_RLO_SUMMARY | DXGI_DEBUG_RLO_DETAIL)); - driver->DXGIDebug->Release(); - driver->DXGIDebug = nullptr; - } - - if (driver->DXGIDebugDLL) - { - UnloadDynamicLibrary(driver->DXGIDebugDLL); - driver->DXGIDebugDLL = nullptr; - } + driver->DXGIDebug->ReportLiveObjects(DXGI_DEBUG_ALL, static_cast(DXGI_DEBUG_RLO_SUMMARY | + DXGI_DEBUG_RLO_DETAIL)); + driver->DXGIDebug->Release(); + driver->DXGIDebug = nullptr; } + + if (driver->DXGIDebugDLL) + { + UnloadDynamicLibrary(driver->DXGIDebugDLL); + driver->DXGIDebugDLL = nullptr; + } + } #endif #define D3D12_GET_DEBUG_INTERFACE_FUNC "D3D12GetDebugInterface" - void InitializeD3D12DebugLayer(NonNullPtr driver) + void InitializeD3D12DebugLayer(NonNullPtr driver) + { + auto D3D12GetDebugInterfaceFunc = + TOD3D12FuncPtr(PFN_D3D12_GET_DEBUG_INTERFACE, LoadFunction(driver->D3D12DLL, D3D12_GET_DEBUG_INTERFACE_FUNC)); + + if (D3D12GetDebugInterfaceFunc == nullptr) { - auto D3D12GetDebugInterfaceFunc = - TOD3D12FuncPtr(PFN_D3D12_GET_DEBUG_INTERFACE, LoadFunction(driver->D3D12DLL, D3D12_GET_DEBUG_INTERFACE_FUNC)); - - if (D3D12GetDebugInterfaceFunc == nullptr) - { - LogWarning(LogCategory::Graphics, "Could not load function: " D3D12_GET_DEBUG_INTERFACE_FUNC); - return; - } - - HRESULT result = D3D12GetDebugInterfaceFunc(IID_ID3D12Debug1, reinterpret_cast(&driver->D3D12Debug)); - if (FAILED(result)) - { - LogWarning(LogCategory::Graphics, "Could not get ID3D12Debug interface"); - return; - } - - driver->D3D12Debug->EnableDebugLayer(); + LogWarning(LogCategory::Graphics, "Could not load function: " D3D12_GET_DEBUG_INTERFACE_FUNC); + return; } - bool InitializeD3D12DebugInfoQueue(NonNullPtr driver) + HRESULT result = D3D12GetDebugInterfaceFunc(IID_ID3D12Debug1, reinterpret_cast(&driver->D3D12Debug)); + if (FAILED(result)) { - ID3D12InfoQueue* infoQueue = nullptr; - D3D12_MESSAGE_SEVERITY severities[] = { D3D12_MESSAGE_SEVERITY_INFO }; - - HRESULT result = driver->D3D12Device->QueryInterface(IID_ID3D12InfoQueue, reinterpret_cast(&infoQueue)); - if (FAILED(result)) - { - D3D12_LogError(driver->D3D12Device, "Failed to convert ID3D12Device to ID3D12InfoQueue", result); - return false; - } - - D3D12_INFO_QUEUE_FILTER filter = {}; - filter.DenyList.NumSeverities = 1; - filter.DenyList.pSeverityList = severities; - infoQueue->PushStorageFilter(&filter); - // infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true); - infoQueue->Release(); - - return true; + LogWarning(LogCategory::Graphics, "Could not get ID3D12Debug interface"); + return; } - void WINAPI OnD3D12DebugInfoMsg(D3D12_MESSAGE_CATEGORY category, D3D12_MESSAGE_SEVERITY severity, - D3D12_MESSAGE_ID id, LPCSTR description, void* /*context*/) + driver->D3D12Debug->EnableDebugLayer(); + } + + bool InitializeD3D12DebugInfoQueue(NonNullPtr driver) + { + ID3D12InfoQueue* infoQueue = nullptr; + D3D12_MESSAGE_SEVERITY severities[] = { D3D12_MESSAGE_SEVERITY_INFO }; + + HRESULT result = driver->D3D12Device->QueryInterface(IID_ID3D12InfoQueue, reinterpret_cast(&infoQueue)); + if (FAILED(result)) { - String catStr = WrapString("UNKNOWN"); - switch (category) - { - case D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED: catStr = WrapString("APPLICATION_DEFINED"); break; - case D3D12_MESSAGE_CATEGORY_MISCELLANEOUS: catStr = WrapString("MISCELLANEOUS"); break; - case D3D12_MESSAGE_CATEGORY_INITIALIZATION: catStr = WrapString("INITIALIZATION"); break; - case D3D12_MESSAGE_CATEGORY_CLEANUP: catStr = WrapString("CLEANUP"); break; - case D3D12_MESSAGE_CATEGORY_COMPILATION: catStr = WrapString("COMPILATION"); break; - case D3D12_MESSAGE_CATEGORY_STATE_CREATION: catStr = WrapString("STATE_CREATION"); break; - case D3D12_MESSAGE_CATEGORY_STATE_SETTING: catStr = WrapString("STATE_SETTING"); break; - case D3D12_MESSAGE_CATEGORY_STATE_GETTING: catStr = WrapString("STATE_GETTING"); break; - case D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION: catStr = WrapString("RESOURCE_MANIPULATION"); break; - case D3D12_MESSAGE_CATEGORY_EXECUTION: catStr = WrapString("EXECUTION"); break; - case D3D12_MESSAGE_CATEGORY_SHADER: catStr = WrapString("SHADER"); break; - } - - String severityStr = WrapString("UNKNOWN"); - switch (severity) - { - case D3D12_MESSAGE_SEVERITY_CORRUPTION: severityStr = WrapString("CORRUPTION"); break; - case D3D12_MESSAGE_SEVERITY_ERROR: severityStr = WrapString("ERROR"); break; - case D3D12_MESSAGE_SEVERITY_WARNING: severityStr = WrapString("WARNING"); break; - case D3D12_MESSAGE_SEVERITY_INFO: severityStr = WrapString("INFO"); break; - case D3D12_MESSAGE_SEVERITY_MESSAGE: severityStr = WrapString("MESSAGE"); break; - } - - if (severity <= D3D12_MESSAGE_SEVERITY_ERROR) - { - LogWarning(LogCategory::Graphics, "D3D12 ERROR: %s [%s %s #%d]", description, CStr(catStr), CStr(severityStr), id); - } - else - { - LogWarning(LogCategory::Graphics, "D3D12 WARNING: %s [%s %s #%d]", description, CStr(catStr), - CStr(severityStr), id); - } + D3D12_LogError(driver->D3D12Device, "Failed to convert ID3D12Device to ID3D12InfoQueue", result); + return false; } - void InitializeD3D12DebugInfoLogger(NonNullPtr driver) - { - // Only supported on Win 11 apparently - ID3D12InfoQueue1* infoQueue = nullptr; - HRESULT result = driver->D3D12Device->QueryInterface(IID_ID3D12InfoQueue1, reinterpret_cast(&infoQueue)); - if (FAILED(result)) - { - return; - } + D3D12_INFO_QUEUE_FILTER filter = {}; + filter.DenyList.NumSeverities = 1; + filter.DenyList.pSeverityList = severities; + infoQueue->PushStorageFilter(&filter); + // infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true); + infoQueue->Release(); - infoQueue->RegisterMessageCallback(OnD3D12DebugInfoMsg, D3D12_MESSAGE_CALLBACK_FLAG_NONE, nullptr, nullptr); - infoQueue->Release(); - Log(LogLevel::Message, LogCategory::Graphics, "DX12: Debug Info Logger Initialized"); + return true; + } + + void WINAPI OnD3D12DebugInfoMsg(D3D12_MESSAGE_CATEGORY category, D3D12_MESSAGE_SEVERITY severity, + D3D12_MESSAGE_ID id, LPCSTR description, void* /*context*/) + { + String catStr = WrapString("UNKNOWN"); + switch (category) + { + case D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED: catStr = WrapString("APPLICATION_DEFINED"); break; + case D3D12_MESSAGE_CATEGORY_MISCELLANEOUS: catStr = WrapString("MISCELLANEOUS"); break; + case D3D12_MESSAGE_CATEGORY_INITIALIZATION: catStr = WrapString("INITIALIZATION"); break; + case D3D12_MESSAGE_CATEGORY_CLEANUP: catStr = WrapString("CLEANUP"); break; + case D3D12_MESSAGE_CATEGORY_COMPILATION: catStr = WrapString("COMPILATION"); break; + case D3D12_MESSAGE_CATEGORY_STATE_CREATION: catStr = WrapString("STATE_CREATION"); break; + case D3D12_MESSAGE_CATEGORY_STATE_SETTING: catStr = WrapString("STATE_SETTING"); break; + case D3D12_MESSAGE_CATEGORY_STATE_GETTING: catStr = WrapString("STATE_GETTING"); break; + case D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION: catStr = WrapString("RESOURCE_MANIPULATION"); break; + case D3D12_MESSAGE_CATEGORY_EXECUTION: catStr = WrapString("EXECUTION"); break; + case D3D12_MESSAGE_CATEGORY_SHADER: catStr = WrapString("SHADER"); break; } + + String severityStr = WrapString("UNKNOWN"); + switch (severity) + { + case D3D12_MESSAGE_SEVERITY_CORRUPTION: severityStr = WrapString("CORRUPTION"); break; + case D3D12_MESSAGE_SEVERITY_ERROR: severityStr = WrapString("ERROR"); break; + case D3D12_MESSAGE_SEVERITY_WARNING: severityStr = WrapString("WARNING"); break; + case D3D12_MESSAGE_SEVERITY_INFO: severityStr = WrapString("INFO"); break; + case D3D12_MESSAGE_SEVERITY_MESSAGE: severityStr = WrapString("MESSAGE"); break; + } + + if (severity <= D3D12_MESSAGE_SEVERITY_ERROR) + { + LogWarning(LogCategory::Graphics, "D3D12 ERROR: %s [%s %s #%d]", description, CStr(catStr), CStr(severityStr), id); + } + else + { + LogWarning(LogCategory::Graphics, "D3D12 WARNING: %s [%s %s #%d]", description, CStr(catStr), CStr(severityStr), id); + } + } + + void InitializeD3D12DebugInfoLogger(NonNullPtr driver) + { + // Only supported on Win 11 apparently + ID3D12InfoQueue1* infoQueue = nullptr; + HRESULT result = driver->D3D12Device->QueryInterface(IID_ID3D12InfoQueue1, reinterpret_cast(&infoQueue)); + if (FAILED(result)) + { + return; + } + + infoQueue->RegisterMessageCallback(OnD3D12DebugInfoMsg, D3D12_MESSAGE_CALLBACK_FLAG_NONE, nullptr, nullptr); + infoQueue->Release(); + Log(LogLevel::Message, LogCategory::Graphics, "DX12: Debug Info Logger Initialized"); + } #endif - // Begin Shaders - Shader* D3D12_CreateShader(NonNullPtr driver, ByteBuffer shaderByteCode, - ShaderCreateInfo& /*shaderCreateInfo*/ JULIET_DEBUG_PARAM(String filename)) + // Begin Shaders + Shader* D3D12_CreateShader(NonNullPtr driver, ByteBuffer shaderByteCode, + ShaderCreateInfo& /*shaderCreateInfo*/ JULIET_DEBUG_PARAM(String filename)) + { + if (!IsValid(shaderByteCode)) { - if (!IsValid(shaderByteCode)) - { - Juliet::LogError(LogCategory::Graphics, "Invalid shader byte code"); - return nullptr; - } - - size_t allocSize = sizeof(D3D12Shader) + shaderByteCode.Size; - auto* shader = static_cast( - ArenaPushSize(driver->DriverArena, allocSize, AlignOf(D3D12Shader), - true JULIET_DEBUG_PARAM("D3D12Shader [{}] | Size [{}]", CStr(filename), shaderByteCode.Size))); - if (!shader) - { - Juliet::LogError(LogCategory::Graphics, "Cannot allocate a new D3D12Shader: Out of memory"); - return nullptr; - } - - // Uses the bytes after the struct to store the shader byte code. - shader->ByteCode.Data = reinterpret_cast(shader + 1); - shader->ByteCode.Size = shaderByteCode.Size; - MemCopy(shader->ByteCode.Data, shaderByteCode.Data, shaderByteCode.Size); - - // Make sure the data is correctly copied - if (MemCompare(shader->ByteCode.Data, shaderByteCode.Data, shaderByteCode.Size) != 0) - { - Juliet::LogError(LogCategory::Graphics, "Memory copy failed"); - Free(shader); - return nullptr; - } - - return reinterpret_cast(shader); + LogError(LogCategory::Graphics, "Invalid shader byte code"); + return nullptr; } - void D3D12_DestroyShader(NonNullPtr /*driver*/, NonNullPtr /*shader*/) + size_t allocSize = sizeof(D3D12Shader) + shaderByteCode.Size; + auto* shader = static_cast( + ArenaPushSize(driver->DriverArena, allocSize, AlignOf(D3D12Shader), + true JULIET_DEBUG_PARAM("D3D12Shader [{}] | Size [{}]", CStr(filename), shaderByteCode.Size))); + if (!shader) { - // For now we never destroy the shader, it stays in the arena. - // If we create too many and need to switch dynamically we will need a way to release the slot for other asset - } - // End Shaders - - // Begin Graphics Pipeline - bool ConvertVertexInputState(const VertexInputState& vertexInputState, D3D12_INPUT_ELEMENT_DESC* desc, String semantic) - { - if (desc == nullptr || vertexInputState.NumVertexAttributes == 0) - { - return false; - } - - for (uint32 idx = 0; idx < vertexInputState.NumVertexAttributes; ++idx) - { - VertexAttribute attribute = vertexInputState.VertexAttributes[idx]; - - desc[idx].SemanticName = CStr(semantic); - desc[idx].SemanticIndex = attribute.Location; - desc[idx].Format = JulietToD3D12_VertexFormat[ToUnderlying(attribute.Format)]; - desc[idx].InputSlot = attribute.BufferSlot; - desc[idx].AlignedByteOffset = attribute.Offset; - desc[idx].InputSlotClass = - JulietToD3D12_InputRate[ToUnderlying(vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InputRate)]; - desc[idx].InstanceDataStepRate = - (vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InputRate == VertexInputRate::Instance) - ? vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InstanceStepRate - : 0; - } - - return true; + LogError(LogCategory::Graphics, "Cannot allocate a new D3D12Shader: Out of memory"); + return nullptr; } - bool ConvertRasterizerState(const RasterizerState& rasterizerState, D3D12_RASTERIZER_DESC& desc) + // Uses the bytes after the struct to store the shader byte code. + shader->ByteCode.Data = reinterpret_cast(shader + 1); + shader->ByteCode.Size = shaderByteCode.Size; + MemCopy(shader->ByteCode.Data, shaderByteCode.Data, shaderByteCode.Size); + + // Make sure the data is correctly copied + if (MemCompare(shader->ByteCode.Data, shaderByteCode.Data, shaderByteCode.Size) != 0) { - desc.FillMode = JulietToD3D12_FillMode[ToUnderlying(rasterizerState.FillMode)]; - desc.CullMode = JulietToD3D12_CullMode[ToUnderlying(rasterizerState.CullMode)]; - - switch (rasterizerState.FrontFace) - { - case FrontFace::CounterClockwise: desc.FrontCounterClockwise = TRUE; break; - case FrontFace::Clockwise: desc.FrontCounterClockwise = FALSE; break; - default: return false; - } - static_assert(ToUnderlying(FrontFace::Count) == 2); - - if (rasterizerState.EnableDepthBias) - { - desc.DepthBias = LRoundF(rasterizerState.DepthBiasConstantFactor); - desc.DepthBiasClamp = rasterizerState.DepthBiasClamp; - desc.SlopeScaledDepthBias = rasterizerState.DepthBiasSlopeFactor; - } - else - { - desc.DepthBias = 0; - desc.DepthBiasClamp = 0.0f; - desc.SlopeScaledDepthBias = 0.0f; - } - - desc.DepthClipEnable = rasterizerState.EnableDepthClip; - desc.MultisampleEnable = FALSE; - desc.AntialiasedLineEnable = FALSE; - desc.ForcedSampleCount = 0; - desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; - return true; + LogError(LogCategory::Graphics, "Memory copy failed"); + Free(shader); + return nullptr; } - bool ConvertBlendState(const GraphicsPipelineCreateInfo& createInfo, D3D12_BLEND_DESC& blendDesc) + return reinterpret_cast(shader); + } + + void D3D12_DestroyShader(NonNullPtr /*driver*/, NonNullPtr /*shader*/) + { + // For now we never destroy the shader, it stays in the arena. + // If we create too many and need to switch dynamically we will need a way to release the slot for other asset + } + // End Shaders + + // Begin Graphics Pipeline + bool ConvertVertexInputState(const VertexInputState& vertexInputState, D3D12_INPUT_ELEMENT_DESC* desc, String semantic) + { + if (desc == nullptr || vertexInputState.NumVertexAttributes == 0) { - ZeroStruct(blendDesc); - blendDesc.AlphaToCoverageEnable = FALSE; - blendDesc.IndependentBlendEnable = FALSE; + return false; + } - for (UINT i = 0; i < GPUDriver::kMaxColorTargetInfo; i += 1) + for (uint32 idx = 0; idx < vertexInputState.NumVertexAttributes; ++idx) + { + VertexAttribute attribute = vertexInputState.VertexAttributes[idx]; + + desc[idx].SemanticName = CStr(semantic); + desc[idx].SemanticIndex = attribute.Location; + desc[idx].Format = JulietToD3D12_VertexFormat[ToUnderlying(attribute.Format)]; + desc[idx].InputSlot = attribute.BufferSlot; + desc[idx].AlignedByteOffset = attribute.Offset; + desc[idx].InputSlotClass = + JulietToD3D12_InputRate[ToUnderlying(vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InputRate)]; + desc[idx].InstanceDataStepRate = + (vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InputRate == VertexInputRate::Instance) + ? vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InstanceStepRate + : 0; + } + + return true; + } + + bool ConvertRasterizerState(const RasterizerState& rasterizerState, D3D12_RASTERIZER_DESC& desc) + { + desc.FillMode = JulietToD3D12_FillMode[ToUnderlying(rasterizerState.FillMode)]; + desc.CullMode = JulietToD3D12_CullMode[ToUnderlying(rasterizerState.CullMode)]; + + switch (rasterizerState.FrontFace) + { + case FrontFace::CounterClockwise: desc.FrontCounterClockwise = TRUE; break; + case FrontFace::Clockwise: desc.FrontCounterClockwise = FALSE; break; + default: return false; + } + static_assert(ToUnderlying(FrontFace::Count) == 2); + + if (rasterizerState.EnableDepthBias) + { + desc.DepthBias = LRoundF(rasterizerState.DepthBiasConstantFactor); + desc.DepthBiasClamp = rasterizerState.DepthBiasClamp; + desc.SlopeScaledDepthBias = rasterizerState.DepthBiasSlopeFactor; + } + else + { + desc.DepthBias = 0; + desc.DepthBiasClamp = 0.0f; + desc.SlopeScaledDepthBias = 0.0f; + } + + desc.DepthClipEnable = rasterizerState.EnableDepthClip; + desc.MultisampleEnable = FALSE; + desc.AntialiasedLineEnable = FALSE; + desc.ForcedSampleCount = 0; + desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; + return true; + } + + bool ConvertBlendState(const GraphicsPipelineCreateInfo& createInfo, D3D12_BLEND_DESC& blendDesc) + { + ZeroStruct(blendDesc); + blendDesc.AlphaToCoverageEnable = FALSE; + blendDesc.IndependentBlendEnable = FALSE; + + for (UINT i = 0; i < GPUDriver::kMaxColorTargetInfo; i += 1) + { + D3D12_RENDER_TARGET_BLEND_DESC rtBlendDesc; + rtBlendDesc.BlendEnable = FALSE; + rtBlendDesc.LogicOpEnable = FALSE; + rtBlendDesc.SrcBlend = D3D12_BLEND_ONE; + rtBlendDesc.DestBlend = D3D12_BLEND_ZERO; + rtBlendDesc.BlendOp = D3D12_BLEND_OP_ADD; + rtBlendDesc.SrcBlendAlpha = D3D12_BLEND_ONE; + rtBlendDesc.DestBlendAlpha = D3D12_BLEND_ZERO; + rtBlendDesc.BlendOpAlpha = D3D12_BLEND_OP_ADD; + rtBlendDesc.LogicOp = D3D12_LOGIC_OP_NOOP; + rtBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + + // If target_info has more blend states, you can set IndependentBlendEnable to TRUE and assign different blend states to each render target slot + if (i < createInfo.TargetInfo.NumColorTargets) { - D3D12_RENDER_TARGET_BLEND_DESC rtBlendDesc; - rtBlendDesc.BlendEnable = FALSE; - rtBlendDesc.LogicOpEnable = FALSE; - rtBlendDesc.SrcBlend = D3D12_BLEND_ONE; - rtBlendDesc.DestBlend = D3D12_BLEND_ZERO; - rtBlendDesc.BlendOp = D3D12_BLEND_OP_ADD; - rtBlendDesc.SrcBlendAlpha = D3D12_BLEND_ONE; - rtBlendDesc.DestBlendAlpha = D3D12_BLEND_ZERO; - rtBlendDesc.BlendOpAlpha = D3D12_BLEND_OP_ADD; - rtBlendDesc.LogicOp = D3D12_LOGIC_OP_NOOP; - rtBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + ColorTargetBlendState blendState = createInfo.TargetInfo.ColorTargetDescriptions[i].BlendState; + ColorComponentFlags colorWriteMask = + blendState.EnableColorWriteMask ? blendState.ColorWriteMask : static_cast(0xF); - // If target_info has more blend states, you can set IndependentBlendEnable to TRUE and assign different blend states to each render target slot - if (i < createInfo.TargetInfo.NumColorTargets) + rtBlendDesc.BlendEnable = blendState.EnableBlend; + rtBlendDesc.SrcBlend = JulietToD3D12_BlendFactor[ToUnderlying(blendState.SourceColorBlendFactor)]; + rtBlendDesc.DestBlend = JulietToD3D12_BlendFactor[ToUnderlying(blendState.DestinationColorBlendFactor)]; + rtBlendDesc.BlendOp = JulietToD3D12_BlendOperation[ToUnderlying(blendState.ColorBlendOperation)]; + rtBlendDesc.SrcBlendAlpha = JulietToD3D12_BlendFactorAlpha[ToUnderlying(blendState.SourceAlphaBlendFactor)]; + rtBlendDesc.DestBlendAlpha = JulietToD3D12_BlendFactorAlpha[ToUnderlying(blendState.DestinationAlphaBlendFactor)]; + rtBlendDesc.BlendOpAlpha = JulietToD3D12_BlendOperation[ToUnderlying(blendState.AlphaBlendOperation)]; + rtBlendDesc.RenderTargetWriteMask = ToUnderlying(colorWriteMask); + + if (i > 0) { - ColorTargetBlendState blendState = createInfo.TargetInfo.ColorTargetDescriptions[i].BlendState; - ColorComponentFlags colorWriteMask = - blendState.EnableColorWriteMask ? blendState.ColorWriteMask : static_cast(0xF); - - rtBlendDesc.BlendEnable = blendState.EnableBlend; - rtBlendDesc.SrcBlend = JulietToD3D12_BlendFactor[ToUnderlying(blendState.SourceColorBlendFactor)]; - rtBlendDesc.DestBlend = JulietToD3D12_BlendFactor[ToUnderlying(blendState.DestinationColorBlendFactor)]; - rtBlendDesc.BlendOp = JulietToD3D12_BlendOperation[ToUnderlying(blendState.ColorBlendOperation)]; - rtBlendDesc.SrcBlendAlpha = JulietToD3D12_BlendFactorAlpha[ToUnderlying(blendState.SourceAlphaBlendFactor)]; - rtBlendDesc.DestBlendAlpha = - JulietToD3D12_BlendFactorAlpha[ToUnderlying(blendState.DestinationAlphaBlendFactor)]; - rtBlendDesc.BlendOpAlpha = JulietToD3D12_BlendOperation[ToUnderlying(blendState.AlphaBlendOperation)]; - rtBlendDesc.RenderTargetWriteMask = ToUnderlying(colorWriteMask); - - if (i > 0) - { - blendDesc.IndependentBlendEnable = TRUE; - } - } - - blendDesc.RenderTarget[i] = rtBlendDesc; - } - - return true; - } - - bool ConvertDepthStencilState(DepthStencilState depthStencilState, D3D12_DEPTH_STENCIL_DESC& desc) - { - desc.DepthEnable = depthStencilState.EnableDepthTest == true ? TRUE : FALSE; - desc.DepthWriteMask = depthStencilState.EnableDepthWrite == true ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; - desc.DepthFunc = JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.CompareOperation)]; - desc.StencilEnable = depthStencilState.EnableStencilTest == true ? TRUE : FALSE; - desc.StencilReadMask = depthStencilState.CompareMask; - desc.StencilWriteMask = depthStencilState.WriteMask; - - desc.FrontFace.StencilFailOp = - JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.FailOperation)]; - desc.FrontFace.StencilDepthFailOp = - JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.DepthFailOperation)]; - desc.FrontFace.StencilPassOp = - JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.PassOperation)]; - desc.FrontFace.StencilFunc = - JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.FrontStencilState.CompareOperation)]; - - desc.BackFace.StencilFailOp = - JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.FailOperation)]; - desc.BackFace.StencilDepthFailOp = - JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.DepthFailOperation)]; - desc.BackFace.StencilPassOp = - JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.PassOperation)]; - desc.BackFace.StencilFunc = - JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.BackStencilState.CompareOperation)]; - - return true; - } - -#if ALLOW_SHADER_HOT_RELOAD - void CopyShader(NonNullPtr destination, NonNullPtr source) - { - D3D12Shader* src = source.Get(); - D3D12Shader* dst = destination.Get(); - - ByteBuffer dstBuffer = dst->ByteCode; - - if (src->ByteCode.Size != dstBuffer.Size) - { - dstBuffer.Data = static_cast(Realloc(dstBuffer.Data, src->ByteCode.Size)); - dstBuffer.Size = src->ByteCode.Size; - } - // Copy the shader data. Infortunately this will overwrite the bytecode if it exists so we patch it back just after - MemCopy(dst, src, sizeof(D3D12Shader)); - dst->ByteCode = dstBuffer; - - MemCopy(dst->ByteCode.Data, src->ByteCode.Data, src->ByteCode.Size); - } -#endif - - void ReleaseGraphicsPipeline(NonNullPtr d3d12GraphicsPipeline) - { - if (d3d12GraphicsPipeline->PipelineState) - { - d3d12GraphicsPipeline->PipelineState->Release(); - } - -#if ALLOW_SHADER_HOT_RELOAD - SafeFree(d3d12GraphicsPipeline->VertexShaderCache); - SafeFree(d3d12GraphicsPipeline->FragmentShaderCache); -#endif - - Free(d3d12GraphicsPipeline.Get()); - } - - GraphicsPipeline* D3D12_CreateGraphicsPipeline(NonNullPtr driver, const GraphicsPipelineCreateInfo& createInfo) - { - auto d3d12Driver = static_cast(driver.Get()); - auto vertexShader = reinterpret_cast(createInfo.VertexShader); - auto fragmentShader = reinterpret_cast(createInfo.FragmentShader); - - D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; - psoDesc.VS.pShaderBytecode = vertexShader->ByteCode.Data; - psoDesc.VS.BytecodeLength = vertexShader->ByteCode.Size; - psoDesc.PS.pShaderBytecode = fragmentShader->ByteCode.Data; // PS == Pixel Shader == Fragment Shader - psoDesc.PS.BytecodeLength = fragmentShader->ByteCode.Size; - - if (createInfo.VertexInputState.NumVertexAttributes > 0) - { - D3D12_INPUT_ELEMENT_DESC inputElementDescs[D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT]; - psoDesc.InputLayout.pInputElementDescs = inputElementDescs; - psoDesc.InputLayout.NumElements = createInfo.VertexInputState.NumVertexAttributes; - ConvertVertexInputState(createInfo.VertexInputState, inputElementDescs, d3d12Driver->Semantic); - } - - psoDesc.PrimitiveTopologyType = JulietToD3D12_PrimitiveTopologyType[ToUnderlying(createInfo.PrimitiveType)]; - - if (!ConvertRasterizerState(createInfo.RasterizerState, psoDesc.RasterizerState)) - { - return nullptr; - } - if (!ConvertBlendState(createInfo, psoDesc.BlendState)) - { - return nullptr; - } - if (!ConvertDepthStencilState(createInfo.DepthStencilState, psoDesc.DepthStencilState)) - { - return nullptr; - } - - auto pipeline = static_cast(Calloc(1, sizeof(D3D12GraphicsPipeline))); - if (!pipeline) - { - return nullptr; - } - - uint32 sampleMask = createInfo.MultisampleState.EnableMask ? createInfo.MultisampleState.SampleMask : 0xFFFFFFFF; - - psoDesc.SampleMask = sampleMask; - psoDesc.SampleDesc.Count = JulietToD3D12_SampleCount[ToUnderlying(createInfo.MultisampleState.SampleCount)]; - psoDesc.SampleDesc.Quality = (createInfo.MultisampleState.SampleCount > TextureSampleCount::One) - ? DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN - : 0; - - psoDesc.DSVFormat = ConvertToD3D12DepthFormat(createInfo.TargetInfo.DepthStencilFormat); - psoDesc.NumRenderTargets = static_cast(createInfo.TargetInfo.NumColorTargets); - for (uint32_t idx = 0; idx < createInfo.TargetInfo.NumColorTargets; ++idx) - { - psoDesc.RTVFormats[idx] = ConvertToD3D12TextureFormat(createInfo.TargetInfo.ColorTargetDescriptions[idx].Format); - } - - // Assuming some default values or further initialization - psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; - psoDesc.CachedPSO.CachedBlobSizeInBytes = 0; - psoDesc.CachedPSO.pCachedBlob = nullptr; - - psoDesc.NodeMask = 0; - - pipeline->RootSignature = d3d12Driver->BindlessRootSignature; - psoDesc.pRootSignature = d3d12Driver->BindlessRootSignature->Handle; - - ID3D12PipelineState* pipelineState; - HRESULT res = d3d12Driver->D3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_ID3D12PipelineState, - reinterpret_cast(&pipelineState)); - if (FAILED(res)) - { - D3D12_LogError(d3d12Driver->D3D12Device, "Could not create graphics pipeline state", res); - ReleaseGraphicsPipeline(pipeline); - return nullptr; - } - - pipeline->PipelineState = pipelineState; - - for (uint32 i = 0; i < createInfo.VertexInputState.NumVertexBufferDescriptions; i += 1) - { - pipeline->VertexStrides[createInfo.VertexInputState.VertexBufferDescriptions[i].Slot] = - createInfo.VertexInputState.VertexBufferDescriptions[i].PitchInBytes; - } - - pipeline->PrimitiveType = createInfo.PrimitiveType; - - pipeline->VertexSamplerCount = vertexShader->NumSamplers; - pipeline->VertexStorageTextureCount = vertexShader->NumStorageTextures; - pipeline->VertexStorageBufferCount = vertexShader->NumStorageBuffers; - pipeline->VertexUniformBufferCount = vertexShader->NumUniformBuffers; - - pipeline->FragmentSamplerCount = fragmentShader->NumSamplers; - pipeline->FragmentStorageTextureCount = fragmentShader->NumStorageTextures; - pipeline->FragmentStorageBufferCount = fragmentShader->NumStorageBuffers; - pipeline->FragmentUniformBufferCount = fragmentShader->NumUniformBuffers; - - pipeline->ReferenceCount = 0; - -#if ALLOW_SHADER_HOT_RELOAD - // Save the PSODesc and shaders to be able to recreate the graphics pipeline when needed - pipeline->PSODescTemplate = psoDesc; - - pipeline->VertexShaderCache = static_cast(Calloc(1, sizeof(D3D12Shader))); - pipeline->FragmentShaderCache = static_cast(Calloc(1, sizeof(D3D12Shader))); - CopyShader(pipeline->VertexShaderCache, vertexShader); - CopyShader(pipeline->FragmentShaderCache, fragmentShader); -#endif - - return reinterpret_cast(pipeline); - } - -#if ALLOW_SHADER_HOT_RELOAD - bool D3D12_UpdateGraphicsPipelineShaders(NonNullPtr driver, NonNullPtr graphicsPipeline, - Shader* optional_vertexShader, Shader* optional_fragmentShader) - { - auto d3d12Driver = static_cast(driver.Get()); - auto d3d12GraphicsPipeline = reinterpret_cast(graphicsPipeline.Get()); - - Assert(d3d12GraphicsPipeline->ReferenceCount == 0 && - "Trying to update a d3d12 graphics pipeline that is currently being used! Call WaitUntilGPUIsIdle " - "before updating!"); - - auto vertexShader = reinterpret_cast(optional_vertexShader); - auto fragmentShader = reinterpret_cast(optional_fragmentShader); - - if (!vertexShader) - { - vertexShader = d3d12GraphicsPipeline->VertexShaderCache; - } - - if (!fragmentShader) - { - fragmentShader = d3d12GraphicsPipeline->FragmentShaderCache; - } - - auto psoDesc = d3d12GraphicsPipeline->PSODescTemplate; - psoDesc.VS.pShaderBytecode = vertexShader->ByteCode.Data; - psoDesc.VS.BytecodeLength = vertexShader->ByteCode.Size; - psoDesc.PS.pShaderBytecode = fragmentShader->ByteCode.Data; - psoDesc.PS.BytecodeLength = fragmentShader->ByteCode.Size; - - psoDesc.pRootSignature = d3d12Driver->BindlessRootSignature->Handle; - - ID3D12PipelineState* pipelineState; - HRESULT res = d3d12Driver->D3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_ID3D12PipelineState, - reinterpret_cast(&pipelineState)); - if (FAILED(res)) - { - D3D12_LogError(d3d12Driver->D3D12Device, "Could not create graphics pipeline state", res); - return false; - } - - d3d12GraphicsPipeline->VertexSamplerCount = vertexShader->NumSamplers; - d3d12GraphicsPipeline->VertexStorageTextureCount = vertexShader->NumStorageTextures; - d3d12GraphicsPipeline->VertexStorageBufferCount = vertexShader->NumStorageBuffers; - d3d12GraphicsPipeline->VertexUniformBufferCount = vertexShader->NumUniformBuffers; - - d3d12GraphicsPipeline->FragmentSamplerCount = fragmentShader->NumSamplers; - d3d12GraphicsPipeline->FragmentStorageTextureCount = fragmentShader->NumStorageTextures; - d3d12GraphicsPipeline->FragmentStorageBufferCount = fragmentShader->NumStorageBuffers; - d3d12GraphicsPipeline->FragmentUniformBufferCount = fragmentShader->NumUniformBuffers; - - // If everything worked, we patch the graphics pipeline and destroy everything irrelevant - if (d3d12GraphicsPipeline->PipelineState) - { - d3d12GraphicsPipeline->PipelineState->Release(); - } - d3d12GraphicsPipeline->PipelineState = pipelineState; - - if (vertexShader != d3d12GraphicsPipeline->VertexShaderCache) - { - CopyShader(d3d12GraphicsPipeline->VertexShaderCache, vertexShader); - } - if (fragmentShader != d3d12GraphicsPipeline->FragmentShaderCache) - { - CopyShader(d3d12GraphicsPipeline->FragmentShaderCache, fragmentShader); - } - - return true; - } -#endif - - // End Graphics Pipeline - - // Begin Descriptor Heap - void DestroyDescriptorHeap(NonNullPtr heap) - { - heap->FreeIndices.Destroy(); - if (heap->Handle) - { - heap->Handle->Release(); - } - } - - D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type, - uint32 count, bool isStaging) - { - D3D12DescriptorHeap* heap = ArenaPushStruct( - driver->DriverArena JULIET_DEBUG_PARAM("Descriptor Heap Type {}", CStr(GetDescriptorTypeNane(type)))); - Assert(heap); - - heap->CurrentDescriptorIndex = 0; - - heap->FreeIndices.Create(driver->DriverArena JULIET_DEBUG_PARAM("DescriptorHeap Free Indices")); - heap->FreeIndices.Resize(16); - heap->CurrentFreeIndex = 0; - - D3D12_DESCRIPTOR_HEAP_DESC heapDesc; - heapDesc.NumDescriptors = count; - heapDesc.Type = type; - heapDesc.Flags = isStaging ? D3D12_DESCRIPTOR_HEAP_FLAG_NONE : D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - heapDesc.NodeMask = 0; - - ID3D12DescriptorHeap* handle; - HRESULT result = driver->D3D12Device->CreateDescriptorHeap(&heapDesc, IID_ID3D12DescriptorHeap, - reinterpret_cast(&handle)); - if (FAILED(result)) - { - D3D12_LogError(driver->D3D12Device, "Failed to create descriptor heap!", result); - DestroyDescriptorHeap(heap); - return nullptr; - } - - heap->Handle = handle; - heap->HeapType = type; - heap->MaxDescriptors = count; - heap->Staging = isStaging; - heap->DescriptorSize = driver->D3D12Device->GetDescriptorHandleIncrementSize(type); - heap->DescriptorHeapCPUStart = handle->GetCPUDescriptorHandleForHeapStart(); - if (!isStaging) - { - heap->DescriptorHeapGPUStart = handle->GetGPUDescriptorHandleForHeapStart(); - } - - return heap; - } - - void CreateDescriptorHeapPool(NonNullPtr driver, D3D12DescriptorHeapPool& heapPool, - D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count) - { - // Heap pool is just single linked list of free elements - constexpr size_t kInitialCapacity = 4; - heapPool.FirstFreeDescriptorHeap = nullptr; - - // Pre allocate 4 - for (uint32 i = 0; i < kInitialCapacity; ++i) - { - D3D12DescriptorHeap* descriptorHeap = CreateDescriptorHeap(driver, type, count, false); - descriptorHeap->Next = heapPool.FirstFreeDescriptorHeap; - heapPool.FirstFreeDescriptorHeap = descriptorHeap; - } - } - - void D3D12_DestroyDescriptorHeapPool(D3D12DescriptorHeapPool& heapPool) - { - D3D12DescriptorHeap* current = heapPool.FirstFreeDescriptorHeap; - while (current != nullptr) - { - D3D12DescriptorHeap* next = current->Next; - DestroyDescriptorHeap(current); - current = next; - } - } - - bool AssignDescriptor(D3D12DescriptorHeap* heap, D3D12Descriptor& outDescriptor) - { - uint32 index = UINT32_MAX; - - if (heap->CurrentFreeIndex > 0) - { - heap->CurrentFreeIndex -= 1; - index = heap->FreeIndices[heap->CurrentFreeIndex]; - } - else if (heap->CurrentDescriptorIndex < heap->MaxDescriptors) - { - index = heap->CurrentDescriptorIndex; - heap->CurrentDescriptorIndex++; - } - else - { - Assert(false, "Descriptor Heap Full!"); - return false; - } - - outDescriptor.Heap = heap; - outDescriptor.Index = index; - outDescriptor.CpuHandle = heap->DescriptorHeapCPUStart; - outDescriptor.CpuHandle.ptr += heap->DescriptorSize * index; - outDescriptor.GpuHandle = heap->DescriptorHeapGPUStart; - outDescriptor.GpuHandle.ptr += heap->DescriptorSize * index; - - return true; - } - - void ReleaseDescriptor(const D3D12Descriptor& descriptor) - { - if (descriptor.Index == UINT32_MAX || descriptor.Heap == nullptr) - { - return; - } - - D3D12DescriptorHeap* heap = descriptor.Heap; - - if (heap->CurrentFreeIndex >= heap->FreeIndices.Count) - { - heap->FreeIndices.PushBack(descriptor.Index); - } - else - { - heap->FreeIndices[heap->CurrentFreeIndex] = descriptor.Index; - heap->CurrentFreeIndex++; - } - } - - D3D12DescriptorHeap* AcquireSamplerHeapFromPool(NonNullPtr d3d12Driver) - { - D3D12DescriptorHeapPool& pool = d3d12Driver->SamplerHeapPool; - - D3D12DescriptorHeap* result = pool.FirstFreeDescriptorHeap; - if (result) - { - pool.FirstFreeDescriptorHeap = pool.FirstFreeDescriptorHeap->Next; - } - else - { - result = CreateDescriptorHeap(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, - GPUDriver::kSampler_HeapDescriptorCount, false); - } - - return result; - } - - void D3D12_ReturnSamplerHeapToPool(NonNullPtr d3d12Driver, NonNullPtr heap) - { - D3D12DescriptorHeapPool& pool = d3d12Driver->SamplerHeapPool; - - heap->CurrentDescriptorIndex = 0; - - heap->Next = pool.FirstFreeDescriptorHeap; - pool.FirstFreeDescriptorHeap = heap; - } - // End Descriptor Heap - - // Begin Staging Descriptors - void InitStagingDescriptorPool(NonNullPtr heap, NonNullPtr pool) - { - for (uint32 idx = 0; idx < kStagingHeapDescriptorExpectedCount; ++idx) - { - pool->FreeDescriptors[idx].Pool = pool; - pool->FreeDescriptors[idx].Heap = heap.Get(); - pool->FreeDescriptors[idx].CpuHandleIndex = idx; - pool->FreeDescriptors[idx].CpuHandle.ptr = heap->DescriptorHeapCPUStart.ptr + (idx * heap->DescriptorSize); - } - } - - bool ExtendStagingDescriptorPool(NonNullPtr driver, D3D12StagingDescriptorPool& pool) - { - D3D12DescriptorHeap* heap = - CreateDescriptorHeap(driver, pool.Heaps[0]->HeapType, kStagingHeapDescriptorExpectedCount, true); - if (!heap) - { - return false; - } - - pool.HeapCount += 1; - pool.Heaps = static_cast(Realloc(pool.Heaps, pool.HeapCount * sizeof(D3D12DescriptorHeap*))); - pool.Heaps[pool.HeapCount - 1] = heap; - - pool.FreeDescriptorCapacity += kStagingHeapDescriptorExpectedCount; - pool.FreeDescriptorCount += kStagingHeapDescriptorExpectedCount; - pool.FreeDescriptors = static_cast( - Realloc(pool.FreeDescriptors, pool.FreeDescriptorCapacity * sizeof(D3D12StagingDescriptor))); - - InitStagingDescriptorPool(heap, &pool); - - return true; - } - - D3D12StagingDescriptorPool* CreateStagingDescriptorPool(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type) - { - D3D12DescriptorHeap* heap = CreateDescriptorHeap(driver, type, kStagingHeapDescriptorExpectedCount, true); - if (!heap) - { - return nullptr; - } - - auto pool = static_cast(Calloc(1, sizeof(D3D12StagingDescriptorPool))); - - // First create the heaps - pool->HeapCount = 1; - pool->Heaps = static_cast(Malloc(sizeof(D3D12DescriptorHeap*))); - pool->Heaps[0] = heap; - - pool->FreeDescriptorCapacity = kStagingHeapDescriptorExpectedCount; - pool->FreeDescriptorCount = kStagingHeapDescriptorExpectedCount; - pool->FreeDescriptors = static_cast( - Malloc(kStagingHeapDescriptorExpectedCount * sizeof(D3D12StagingDescriptor))); - - InitStagingDescriptorPool(heap, pool); - - return pool; - } - - bool AssignStagingDescriptor(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12StagingDescriptor& outDescriptor) - { - // TODO: Make it thread safe - D3D12StagingDescriptor* descriptor = nullptr; - D3D12StagingDescriptorPool* pool = driver->StagingDescriptorPools[type]; - - if (pool->FreeDescriptorCount == 0) - { - if (!ExtendStagingDescriptorPool(driver, *pool)) - { - return false; + blendDesc.IndependentBlendEnable = TRUE; } } - descriptor = &pool->FreeDescriptors[pool->FreeDescriptorCount - 1]; - MemCopy(&outDescriptor, descriptor, sizeof(D3D12StagingDescriptor)); - pool->FreeDescriptorCount -= 1; - - return true; + blendDesc.RenderTarget[i] = rtBlendDesc; } - void ReleaseStagingDescriptor(NonNullPtr /*driver*/, D3D12StagingDescriptor& cpuDescriptor) - { - D3D12StagingDescriptorPool* pool = cpuDescriptor.Pool; + return true; + } - if (pool != nullptr) + bool ConvertDepthStencilState(DepthStencilState depthStencilState, D3D12_DEPTH_STENCIL_DESC& desc) + { + desc.DepthEnable = depthStencilState.EnableDepthTest == true ? TRUE : FALSE; + desc.DepthWriteMask = depthStencilState.EnableDepthWrite == true ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; + desc.DepthFunc = JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.CompareOperation)]; + desc.StencilEnable = depthStencilState.EnableStencilTest == true ? TRUE : FALSE; + desc.StencilReadMask = depthStencilState.CompareMask; + desc.StencilWriteMask = depthStencilState.WriteMask; + + desc.FrontFace.StencilFailOp = + JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.FailOperation)]; + desc.FrontFace.StencilDepthFailOp = + JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.DepthFailOperation)]; + desc.FrontFace.StencilPassOp = + JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.PassOperation)]; + desc.FrontFace.StencilFunc = + JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.FrontStencilState.CompareOperation)]; + + desc.BackFace.StencilFailOp = + JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.FailOperation)]; + desc.BackFace.StencilDepthFailOp = + JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.DepthFailOperation)]; + desc.BackFace.StencilPassOp = + JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.PassOperation)]; + desc.BackFace.StencilFunc = + JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.BackStencilState.CompareOperation)]; + + return true; + } + +#if ALLOW_SHADER_HOT_RELOAD + void CopyShader(NonNullPtr destination, NonNullPtr source) + { + D3D12Shader* src = source.Get(); + D3D12Shader* dst = destination.Get(); + + ByteBuffer dstBuffer = dst->ByteCode; + + if (src->ByteCode.Size != dstBuffer.Size) + { + dstBuffer.Data = static_cast(Realloc(dstBuffer.Data, src->ByteCode.Size)); + dstBuffer.Size = src->ByteCode.Size; + } + // Copy the shader data. Infortunately this will overwrite the bytecode if it exists so we patch it back just after + MemCopy(dst, src, sizeof(D3D12Shader)); + dst->ByteCode = dstBuffer; + + MemCopy(dst->ByteCode.Data, src->ByteCode.Data, src->ByteCode.Size); + } +#endif + + void ReleaseGraphicsPipeline(NonNullPtr d3d12GraphicsPipeline) + { + if (d3d12GraphicsPipeline->PipelineState) + { + d3d12GraphicsPipeline->PipelineState->Release(); + } + +#if ALLOW_SHADER_HOT_RELOAD + SafeFree(d3d12GraphicsPipeline->VertexShaderCache); + SafeFree(d3d12GraphicsPipeline->FragmentShaderCache); +#endif + + Free(d3d12GraphicsPipeline.Get()); + } + + GraphicsPipeline* D3D12_CreateGraphicsPipeline(NonNullPtr driver, const GraphicsPipelineCreateInfo& createInfo) + { + auto d3d12Driver = static_cast(driver.Get()); + auto vertexShader = reinterpret_cast(createInfo.VertexShader); + auto fragmentShader = reinterpret_cast(createInfo.FragmentShader); + + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + psoDesc.VS.pShaderBytecode = vertexShader->ByteCode.Data; + psoDesc.VS.BytecodeLength = vertexShader->ByteCode.Size; + psoDesc.PS.pShaderBytecode = fragmentShader->ByteCode.Data; // PS == Pixel Shader == Fragment Shader + psoDesc.PS.BytecodeLength = fragmentShader->ByteCode.Size; + + if (createInfo.VertexInputState.NumVertexAttributes > 0) + { + D3D12_INPUT_ELEMENT_DESC inputElementDescs[D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT]; + psoDesc.InputLayout.pInputElementDescs = inputElementDescs; + psoDesc.InputLayout.NumElements = createInfo.VertexInputState.NumVertexAttributes; + ConvertVertexInputState(createInfo.VertexInputState, inputElementDescs, d3d12Driver->Semantic); + } + + psoDesc.PrimitiveTopologyType = JulietToD3D12_PrimitiveTopologyType[ToUnderlying(createInfo.PrimitiveType)]; + + if (!ConvertRasterizerState(createInfo.RasterizerState, psoDesc.RasterizerState)) + { + return nullptr; + } + if (!ConvertBlendState(createInfo, psoDesc.BlendState)) + { + return nullptr; + } + if (!ConvertDepthStencilState(createInfo.DepthStencilState, psoDesc.DepthStencilState)) + { + return nullptr; + } + + auto pipeline = static_cast(Calloc(1, sizeof(D3D12GraphicsPipeline))); + if (!pipeline) + { + return nullptr; + } + + uint32 sampleMask = createInfo.MultisampleState.EnableMask ? createInfo.MultisampleState.SampleMask : 0xFFFFFFFF; + + psoDesc.SampleMask = sampleMask; + psoDesc.SampleDesc.Count = JulietToD3D12_SampleCount[ToUnderlying(createInfo.MultisampleState.SampleCount)]; + psoDesc.SampleDesc.Quality = + (createInfo.MultisampleState.SampleCount > TextureSampleCount::One) ? DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN : 0; + + psoDesc.DSVFormat = ConvertToD3D12DepthFormat(createInfo.TargetInfo.DepthStencilFormat); + psoDesc.NumRenderTargets = static_cast(createInfo.TargetInfo.NumColorTargets); + for (uint32_t idx = 0; idx < createInfo.TargetInfo.NumColorTargets; ++idx) + { + psoDesc.RTVFormats[idx] = ConvertToD3D12TextureFormat(createInfo.TargetInfo.ColorTargetDescriptions[idx].Format); + } + + // Assuming some default values or further initialization + psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; + psoDesc.CachedPSO.CachedBlobSizeInBytes = 0; + psoDesc.CachedPSO.pCachedBlob = nullptr; + + psoDesc.NodeMask = 0; + + pipeline->RootSignature = d3d12Driver->BindlessRootSignature; + psoDesc.pRootSignature = d3d12Driver->BindlessRootSignature->Handle; + + ID3D12PipelineState* pipelineState; + HRESULT res = d3d12Driver->D3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_ID3D12PipelineState, + reinterpret_cast(&pipelineState)); + if (FAILED(res)) + { + D3D12_LogError(d3d12Driver->D3D12Device, "Could not create graphics pipeline state", res); + ReleaseGraphicsPipeline(pipeline); + return nullptr; + } + + pipeline->PipelineState = pipelineState; + + for (uint32 i = 0; i < createInfo.VertexInputState.NumVertexBufferDescriptions; i += 1) + { + pipeline->VertexStrides[createInfo.VertexInputState.VertexBufferDescriptions[i].Slot] = + createInfo.VertexInputState.VertexBufferDescriptions[i].PitchInBytes; + } + + pipeline->PrimitiveType = createInfo.PrimitiveType; + + pipeline->VertexSamplerCount = vertexShader->NumSamplers; + pipeline->VertexStorageTextureCount = vertexShader->NumStorageTextures; + pipeline->VertexStorageBufferCount = vertexShader->NumStorageBuffers; + pipeline->VertexUniformBufferCount = vertexShader->NumUniformBuffers; + + pipeline->FragmentSamplerCount = fragmentShader->NumSamplers; + pipeline->FragmentStorageTextureCount = fragmentShader->NumStorageTextures; + pipeline->FragmentStorageBufferCount = fragmentShader->NumStorageBuffers; + pipeline->FragmentUniformBufferCount = fragmentShader->NumUniformBuffers; + + pipeline->ReferenceCount = 0; + +#if ALLOW_SHADER_HOT_RELOAD + // Save the PSODesc and shaders to be able to recreate the graphics pipeline when needed + pipeline->PSODescTemplate = psoDesc; + + pipeline->VertexShaderCache = static_cast(Calloc(1, sizeof(D3D12Shader))); + pipeline->FragmentShaderCache = static_cast(Calloc(1, sizeof(D3D12Shader))); + CopyShader(pipeline->VertexShaderCache, vertexShader); + CopyShader(pipeline->FragmentShaderCache, fragmentShader); +#endif + + return reinterpret_cast(pipeline); + } + +#if ALLOW_SHADER_HOT_RELOAD + bool D3D12_UpdateGraphicsPipelineShaders(NonNullPtr driver, NonNullPtr graphicsPipeline, + Shader* optional_vertexShader, Shader* optional_fragmentShader) + { + auto d3d12Driver = static_cast(driver.Get()); + auto d3d12GraphicsPipeline = reinterpret_cast(graphicsPipeline.Get()); + + Assert(d3d12GraphicsPipeline->ReferenceCount == 0 && + "Trying to update a d3d12 graphics pipeline that is currently being used! Call WaitUntilGPUIsIdle " + "before updating!"); + + auto vertexShader = reinterpret_cast(optional_vertexShader); + auto fragmentShader = reinterpret_cast(optional_fragmentShader); + + if (!vertexShader) + { + vertexShader = d3d12GraphicsPipeline->VertexShaderCache; + } + + if (!fragmentShader) + { + fragmentShader = d3d12GraphicsPipeline->FragmentShaderCache; + } + + auto psoDesc = d3d12GraphicsPipeline->PSODescTemplate; + psoDesc.VS.pShaderBytecode = vertexShader->ByteCode.Data; + psoDesc.VS.BytecodeLength = vertexShader->ByteCode.Size; + psoDesc.PS.pShaderBytecode = fragmentShader->ByteCode.Data; + psoDesc.PS.BytecodeLength = fragmentShader->ByteCode.Size; + + psoDesc.pRootSignature = d3d12Driver->BindlessRootSignature->Handle; + + ID3D12PipelineState* pipelineState; + HRESULT res = d3d12Driver->D3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_ID3D12PipelineState, + reinterpret_cast(&pipelineState)); + if (FAILED(res)) + { + D3D12_LogError(d3d12Driver->D3D12Device, "Could not create graphics pipeline state", res); + return false; + } + + d3d12GraphicsPipeline->VertexSamplerCount = vertexShader->NumSamplers; + d3d12GraphicsPipeline->VertexStorageTextureCount = vertexShader->NumStorageTextures; + d3d12GraphicsPipeline->VertexStorageBufferCount = vertexShader->NumStorageBuffers; + d3d12GraphicsPipeline->VertexUniformBufferCount = vertexShader->NumUniformBuffers; + + d3d12GraphicsPipeline->FragmentSamplerCount = fragmentShader->NumSamplers; + d3d12GraphicsPipeline->FragmentStorageTextureCount = fragmentShader->NumStorageTextures; + d3d12GraphicsPipeline->FragmentStorageBufferCount = fragmentShader->NumStorageBuffers; + d3d12GraphicsPipeline->FragmentUniformBufferCount = fragmentShader->NumUniformBuffers; + + // If everything worked, we patch the graphics pipeline and destroy everything irrelevant + if (d3d12GraphicsPipeline->PipelineState) + { + d3d12GraphicsPipeline->PipelineState->Release(); + } + d3d12GraphicsPipeline->PipelineState = pipelineState; + + if (vertexShader != d3d12GraphicsPipeline->VertexShaderCache) + { + CopyShader(d3d12GraphicsPipeline->VertexShaderCache, vertexShader); + } + if (fragmentShader != d3d12GraphicsPipeline->FragmentShaderCache) + { + CopyShader(d3d12GraphicsPipeline->FragmentShaderCache, fragmentShader); + } + + return true; + } +#endif + + // End Graphics Pipeline + + // Begin Descriptor Heap + void DestroyDescriptorHeap(NonNullPtr heap) + { + heap->FreeIndices.Destroy(); + if (heap->Handle) + { + heap->Handle->Release(); + } + } + + D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count, bool isStaging) + { + D3D12DescriptorHeap* heap = ArenaPushStruct( + driver->DriverArena JULIET_DEBUG_PARAM("Descriptor Heap Type {}", CStr(GetDescriptorTypeNane(type)))); + Assert(heap); + + heap->CurrentDescriptorIndex = 0; + + heap->FreeIndices.Create(driver->DriverArena JULIET_DEBUG_PARAM("DescriptorHeap Free Indices")); + heap->FreeIndices.Resize(16); + heap->CurrentFreeIndex = 0; + + D3D12_DESCRIPTOR_HEAP_DESC heapDesc; + heapDesc.NumDescriptors = count; + heapDesc.Type = type; + heapDesc.Flags = isStaging ? D3D12_DESCRIPTOR_HEAP_FLAG_NONE : D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + heapDesc.NodeMask = 0; + + ID3D12DescriptorHeap* handle; + HRESULT result = + driver->D3D12Device->CreateDescriptorHeap(&heapDesc, IID_ID3D12DescriptorHeap, reinterpret_cast(&handle)); + if (FAILED(result)) + { + D3D12_LogError(driver->D3D12Device, "Failed to create descriptor heap!", result); + DestroyDescriptorHeap(heap); + return nullptr; + } + + heap->Handle = handle; + heap->HeapType = type; + heap->MaxDescriptors = count; + heap->Staging = isStaging; + heap->DescriptorSize = driver->D3D12Device->GetDescriptorHandleIncrementSize(type); + heap->DescriptorHeapCPUStart = handle->GetCPUDescriptorHandleForHeapStart(); + if (!isStaging) + { + heap->DescriptorHeapGPUStart = handle->GetGPUDescriptorHandleForHeapStart(); + } + + return heap; + } + + void CreateDescriptorHeapPool(NonNullPtr driver, D3D12DescriptorHeapPool& heapPool, + D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count) + { + // Heap pool is just single linked list of free elements + constexpr size_t kInitialCapacity = 4; + heapPool.FirstFreeDescriptorHeap = nullptr; + + // Pre allocate 4 + for (uint32 i = 0; i < kInitialCapacity; ++i) + { + D3D12DescriptorHeap* descriptorHeap = CreateDescriptorHeap(driver, type, count, false); + descriptorHeap->Next = heapPool.FirstFreeDescriptorHeap; + heapPool.FirstFreeDescriptorHeap = descriptorHeap; + } + } + + void D3D12_DestroyDescriptorHeapPool(D3D12DescriptorHeapPool& heapPool) + { + D3D12DescriptorHeap* current = heapPool.FirstFreeDescriptorHeap; + while (current != nullptr) + { + D3D12DescriptorHeap* next = current->Next; + DestroyDescriptorHeap(current); + current = next; + } + } + + bool AssignDescriptor(D3D12DescriptorHeap* heap, D3D12Descriptor& outDescriptor) + { + uint32 index = UINT32_MAX; + + if (heap->CurrentFreeIndex > 0) + { + heap->CurrentFreeIndex -= 1; + index = heap->FreeIndices[heap->CurrentFreeIndex]; + } + else if (heap->CurrentDescriptorIndex < heap->MaxDescriptors) + { + index = heap->CurrentDescriptorIndex; + heap->CurrentDescriptorIndex++; + } + else + { + Assert(false, "Descriptor Heap Full!"); + return false; + } + + outDescriptor.Heap = heap; + outDescriptor.Index = index; + outDescriptor.CpuHandle = heap->DescriptorHeapCPUStart; + outDescriptor.CpuHandle.ptr += heap->DescriptorSize * index; + outDescriptor.GpuHandle = heap->DescriptorHeapGPUStart; + outDescriptor.GpuHandle.ptr += heap->DescriptorSize * index; + + return true; + } + + void ReleaseDescriptor(const D3D12Descriptor& descriptor) + { + if (descriptor.Index == UINT32_MAX || descriptor.Heap == nullptr) + { + return; + } + + D3D12DescriptorHeap* heap = descriptor.Heap; + + if (heap->CurrentFreeIndex >= heap->FreeIndices.Count) + { + heap->FreeIndices.PushBack(descriptor.Index); + } + else + { + heap->FreeIndices[heap->CurrentFreeIndex] = descriptor.Index; + heap->CurrentFreeIndex++; + } + } + + D3D12DescriptorHeap* AcquireSamplerHeapFromPool(NonNullPtr d3d12Driver) + { + D3D12DescriptorHeapPool& pool = d3d12Driver->SamplerHeapPool; + + D3D12DescriptorHeap* result = pool.FirstFreeDescriptorHeap; + if (result) + { + pool.FirstFreeDescriptorHeap = pool.FirstFreeDescriptorHeap->Next; + } + else + { + result = CreateDescriptorHeap(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, + GPUDriver::kSampler_HeapDescriptorCount, false); + } + + return result; + } + + void D3D12_ReturnSamplerHeapToPool(NonNullPtr d3d12Driver, NonNullPtr heap) + { + D3D12DescriptorHeapPool& pool = d3d12Driver->SamplerHeapPool; + + heap->CurrentDescriptorIndex = 0; + + heap->Next = pool.FirstFreeDescriptorHeap; + pool.FirstFreeDescriptorHeap = heap; + } + // End Descriptor Heap + + // Begin Staging Descriptors + void InitStagingDescriptorPool(NonNullPtr heap, NonNullPtr pool) + { + for (uint32 idx = 0; idx < kStagingHeapDescriptorExpectedCount; ++idx) + { + pool->FreeDescriptors[idx].Pool = pool; + pool->FreeDescriptors[idx].Heap = heap.Get(); + pool->FreeDescriptors[idx].CpuHandleIndex = idx; + pool->FreeDescriptors[idx].CpuHandle.ptr = heap->DescriptorHeapCPUStart.ptr + (idx * heap->DescriptorSize); + } + } + + bool ExtendStagingDescriptorPool(NonNullPtr driver, D3D12StagingDescriptorPool& pool) + { + D3D12DescriptorHeap* heap = + CreateDescriptorHeap(driver, pool.Heaps[0]->HeapType, kStagingHeapDescriptorExpectedCount, true); + if (!heap) + { + return false; + } + + pool.HeapCount += 1; + pool.Heaps = static_cast(Realloc(pool.Heaps, pool.HeapCount * sizeof(D3D12DescriptorHeap*))); + pool.Heaps[pool.HeapCount - 1] = heap; + + pool.FreeDescriptorCapacity += kStagingHeapDescriptorExpectedCount; + pool.FreeDescriptorCount += kStagingHeapDescriptorExpectedCount; + pool.FreeDescriptors = static_cast( + Realloc(pool.FreeDescriptors, pool.FreeDescriptorCapacity * sizeof(D3D12StagingDescriptor))); + + InitStagingDescriptorPool(heap, &pool); + + return true; + } + + D3D12StagingDescriptorPool* CreateStagingDescriptorPool(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type) + { + D3D12DescriptorHeap* heap = CreateDescriptorHeap(driver, type, kStagingHeapDescriptorExpectedCount, true); + if (!heap) + { + return nullptr; + } + + auto pool = static_cast(Calloc(1, sizeof(D3D12StagingDescriptorPool))); + + // First create the heaps + pool->HeapCount = 1; + pool->Heaps = static_cast(Malloc(sizeof(D3D12DescriptorHeap*))); + pool->Heaps[0] = heap; + + pool->FreeDescriptorCapacity = kStagingHeapDescriptorExpectedCount; + pool->FreeDescriptorCount = kStagingHeapDescriptorExpectedCount; + pool->FreeDescriptors = + static_cast(Malloc(kStagingHeapDescriptorExpectedCount * sizeof(D3D12StagingDescriptor))); + + InitStagingDescriptorPool(heap, pool); + + return pool; + } + + bool AssignStagingDescriptor(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12StagingDescriptor& outDescriptor) + { + // TODO: Make it thread safe + D3D12StagingDescriptor* descriptor = nullptr; + D3D12StagingDescriptorPool* pool = driver->StagingDescriptorPools[type]; + + if (pool->FreeDescriptorCount == 0) + { + if (!ExtendStagingDescriptorPool(driver, *pool)) { - MemCopy(&pool->FreeDescriptors[pool->FreeDescriptorCount], &cpuDescriptor, sizeof(D3D12StagingDescriptor)); - pool->FreeDescriptorCount += 1; + return false; } } - void DestroyStagingDescriptorPool(NonNullPtr pool) + descriptor = &pool->FreeDescriptors[pool->FreeDescriptorCount - 1]; + MemCopy(&outDescriptor, descriptor, sizeof(D3D12StagingDescriptor)); + pool->FreeDescriptorCount -= 1; + + return true; + } + + void ReleaseStagingDescriptor(NonNullPtr /*driver*/, D3D12StagingDescriptor& cpuDescriptor) + { + D3D12StagingDescriptorPool* pool = cpuDescriptor.Pool; + + if (pool != nullptr) { - for (uint32 i = 0; i < pool->HeapCount; i += 1) - { - DestroyDescriptorHeap(pool->Heaps[i]); - } - - Free(pool->Heaps); - Free(pool->FreeDescriptors); - - Free(pool.Get()); + MemCopy(&pool->FreeDescriptors[pool->FreeDescriptorCount], &cpuDescriptor, sizeof(D3D12StagingDescriptor)); + pool->FreeDescriptorCount += 1; } - // End Staging Descriptors + } - // Begin Buffers - // Linked List of free buffers - D3D12Buffer* FreeBuffers = nullptr; - - enum class D3D12BufferType : uint8 + void DestroyStagingDescriptorPool(NonNullPtr pool) + { + for (uint32 i = 0; i < pool->HeapCount; i += 1) { - Base, - TransferDownload, - TransferUpload, - }; - - [[nodiscard]] const char* D3D12BufferTypeToString(D3D12BufferType type) - { - switch (type) - { - case D3D12BufferType::Base: return "Base"; - case D3D12BufferType::TransferDownload: return "TransferDownload"; - case D3D12BufferType::TransferUpload: return "TransferUpload"; - } - return "Unknown"; + DestroyDescriptorHeap(pool->Heaps[i]); } - [[nodiscard]] const char* BufferUsageToString(BufferUsage usage) + Free(pool->Heaps); + Free(pool->FreeDescriptors); + + Free(pool.Get()); + } + // End Staging Descriptors + + // Begin Buffers + // Linked List of free buffers + D3D12Buffer* FreeBuffers = nullptr; + + enum class D3D12BufferType : uint8 + { + Base, + TransferDownload, + TransferUpload, + }; + + [[nodiscard]] const char* D3D12BufferTypeToString(D3D12BufferType type) + { + switch (type) { - switch (usage) - { - case BufferUsage::None: return "None"; - case BufferUsage::ConstantBuffer: return "ConstantBuffer"; - case BufferUsage::StructuredBuffer: return "StructuredBuffer"; - case BufferUsage::IndexBuffer: return "IndexBuffer"; - } - return "Unknown"; + case D3D12BufferType::Base: return "Base"; + case D3D12BufferType::TransferDownload: return "TransferDownload"; + case D3D12BufferType::TransferUpload: return "TransferUpload"; + } + return "Unknown"; + } + + [[nodiscard]] const char* BufferUsageToString(BufferUsage usage) + { + switch (usage) + { + case BufferUsage::None: return "None"; + case BufferUsage::ConstantBuffer: return "ConstantBuffer"; + case BufferUsage::StructuredBuffer: return "StructuredBuffer"; + case BufferUsage::IndexBuffer: return "IndexBuffer"; + } + return "Unknown"; + } + + void DestroyBuffer(D3D12Buffer* buffer) + { + if (!buffer) + { + return; } - void DestroyBuffer(D3D12Buffer* buffer) + if (buffer->Descriptor.Index != UINT32_MAX) { - if (!buffer) - { - return; - } + ReleaseDescriptor(buffer->Descriptor); + } + buffer->Descriptor = {}; - if (buffer->Descriptor.Index != UINT32_MAX) - { - ReleaseDescriptor(buffer->Descriptor); - } - buffer->Descriptor = {}; + if (buffer->Handle) + { + buffer->Handle->Release(); + buffer->Handle = nullptr; + } + buffer->CurrentState = D3D12_RESOURCE_STATE_COMMON; + buffer->Size = 0; - if (buffer->Handle) - { - buffer->Handle->Release(); - buffer->Handle = nullptr; - } - buffer->CurrentState = D3D12_RESOURCE_STATE_COMMON; - buffer->Size = 0; + buffer->Next = FreeBuffers; + FreeBuffers = buffer; + } - buffer->Next = FreeBuffers; - FreeBuffers = buffer; + D3D12Buffer* CreateBuffer(NonNullPtr d3d12Driver, size_t size, size_t stride, BufferUsage usage, + D3D12BufferType type, bool isDynamic) + { + D3D12Buffer* buffer = nullptr; + if (FreeBuffers) + { + buffer = FreeBuffers; + FreeBuffers = buffer->Next; + buffer->Next = nullptr; } - D3D12Buffer* CreateBuffer(NonNullPtr d3d12Driver, size_t size, size_t stride, BufferUsage usage, - D3D12BufferType type, bool isDynamic) + if (!buffer) { - D3D12Buffer* buffer = nullptr; - if (FreeBuffers) - { - buffer = FreeBuffers; - FreeBuffers = buffer->Next; - buffer->Next = nullptr; - } + buffer = ArenaPushStruct(d3d12Driver->DriverArena JULIET_DEBUG_PARAM("D3D12Buffer")); + } - if (!buffer) - { - buffer = ArenaPushStruct(d3d12Driver->DriverArena JULIET_DEBUG_PARAM("D3D12Buffer")); - } + if (!buffer) + { + return nullptr; + } - if (!buffer) - { - return nullptr; - } + if (type == D3D12BufferType::Base && usage == BufferUsage::None) + { + Assert(false, "Creating Base buffer with BufferUsage::None is invalid"); + DestroyBuffer(buffer); + return nullptr; + } - if (type == D3D12BufferType::Base && usage == BufferUsage::None) - { - Assert(false, "Creating Base buffer with BufferUsage::None is invalid"); - DestroyBuffer(buffer); - return nullptr; - } + // Align size for Constant Buffers + if (usage == BufferUsage::ConstantBuffer) + { + size = (size + 255U) & ~255U; + } - // Align size for Constant Buffers - if (usage == BufferUsage::ConstantBuffer) - { - size = (size + 255U) & ~255U; - } + D3D12_HEAP_PROPERTIES heapProperties = {}; + heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - D3D12_HEAP_PROPERTIES heapProperties = {}; - heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON; + D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE; - D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON; - D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE; + // Constant buffers or Dynamic buffers generally need to be uploaded every frame + const bool isUpload = isDynamic || (type == D3D12BufferType::TransferUpload) || (usage == BufferUsage::ConstantBuffer); - // Constant buffers or Dynamic buffers generally need to be uploaded every frame - const bool isUpload = isDynamic || (type == D3D12BufferType::TransferUpload) || (usage == BufferUsage::ConstantBuffer); - - if (type == D3D12BufferType::TransferDownload) + if (type == D3D12BufferType::TransferDownload) + { + heapProperties.Type = D3D12_HEAP_TYPE_READBACK; + initialState = D3D12_RESOURCE_STATE_COPY_DEST; + } + else if (isUpload) + { + if (d3d12Driver->GPUUploadHeapSupported) { - heapProperties.Type = D3D12_HEAP_TYPE_READBACK; - initialState = D3D12_RESOURCE_STATE_COPY_DEST; - } - else if (isUpload) - { - if (d3d12Driver->GPUUploadHeapSupported) - { - heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD; - initialState = D3D12_RESOURCE_STATE_COMMON; - } - else - { - heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD; - initialState = D3D12_RESOURCE_STATE_GENERIC_READ; - } - } - else - { - // Must be a static buffer (Base type) - heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT; + heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD; initialState = D3D12_RESOURCE_STATE_COMMON; } - - D3D12_RESOURCE_DESC desc = {}; - desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - desc.Alignment = 0; - desc.Width = size; - desc.Height = 1; - desc.DepthOrArraySize = 1; - desc.MipLevels = 1; - desc.Format = DXGI_FORMAT_UNKNOWN; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - desc.Flags = D3D12_RESOURCE_FLAG_NONE; - - Log(LogLevel::Message, LogCategory::Graphics, "CreateBuffer: Device=%p, Size=%zu, Type=%s Use=%s", - (void*)d3d12Driver->D3D12Device, size, D3D12BufferTypeToString(type), BufferUsageToString(usage)); - - ID3D12Resource* handle = nullptr; - HRESULT result = d3d12Driver->D3D12Device->CreateCommittedResource(&heapProperties, heapFlags, &desc, - initialState, nullptr, IID_ID3D12Resource, - reinterpret_cast(&handle)); - - if (FAILED(result)) - { - Log(LogLevel::Error, LogCategory::Graphics, "Could not create buffer! HRESULT=0x%08X", static_cast(result)); - Log(LogLevel::Error, LogCategory::Graphics, "Failed Desc: Width=%llu Layout=%d HeapType=%d", - (unsigned long long)desc.Width, (int)desc.Layout, (int)heapProperties.Type); - - HRESULT removeReason = d3d12Driver->D3D12Device->GetDeviceRemovedReason(); - if (FAILED(removeReason)) - { - Log(LogLevel::Error, LogCategory::Graphics, "Device Removed Reason: 0x%08X", static_cast(removeReason)); - } - - DestroyBuffer(buffer); - return nullptr; - } - - buffer->Handle = handle; - buffer->CurrentState = initialState; - buffer->Descriptor.Index = UINT32_MAX; - buffer->Size = size; - - if (usage == BufferUsage::ConstantBuffer || usage == BufferUsage::StructuredBuffer) - { - auto& heap = d3d12Driver->BindlessDescriptorHeap; - - D3D12Descriptor descriptor; - if (AssignDescriptor(heap, descriptor)) - { - buffer->Descriptor = descriptor; - - D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = descriptor.CpuHandle; - - if (usage == BufferUsage::ConstantBuffer) - { - D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; - cbvDesc.BufferLocation = handle->GetGPUVirtualAddress(); - cbvDesc.SizeInBytes = static_cast(size); - d3d12Driver->D3D12Device->CreateConstantBufferView(&cbvDesc, cpuHandle); - } - else if (usage == BufferUsage::StructuredBuffer) - { - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; - srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - srvDesc.Buffer.FirstElement = 0; - - if (stride > 0) - { - srvDesc.Format = DXGI_FORMAT_UNKNOWN; - srvDesc.Buffer.NumElements = static_cast(size / stride); - srvDesc.Buffer.StructureByteStride = static_cast(stride); - srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; - } - else - { - srvDesc.Format = DXGI_FORMAT_R32_TYPELESS; - srvDesc.Buffer.NumElements = static_cast(size / 4); - srvDesc.Buffer.StructureByteStride = 0; - srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW; - } - - d3d12Driver->D3D12Device->CreateShaderResourceView(handle, &srvDesc, cpuHandle); - Log(LogLevel::Message, LogCategory::Graphics, " -> SRV DescriptorIndex=%u", descriptor.Index); - } - } - else - { - Juliet::LogError(LogCategory::Graphics, "Bindless Heap Full or Invalid!"); - } - } - - return buffer; - } - - GraphicsBuffer* D3D12_CreateGraphicsBuffer(NonNullPtr driver, size_t size, size_t stride, - BufferUsage usage, bool isDynamic) - { - auto d3d12Driver = static_cast(driver.Get()); - return reinterpret_cast(CreateBuffer(d3d12Driver, size, stride, usage, D3D12BufferType::Base, isDynamic)); - } - - void D3D12_DestroyGraphicsBuffer(NonNullPtr buffer) - { - DestroyBuffer(reinterpret_cast(buffer.Get())); - } - - GraphicsTransferBuffer* D3D12_CreateGraphicsTransferBuffer(NonNullPtr driver, size_t size, TransferBufferUsage usage) - { - auto d3d12Driver = static_cast(driver.Get()); - return reinterpret_cast( - CreateBuffer(d3d12Driver, size, 0, BufferUsage::None, - usage == TransferBufferUsage::Upload ? D3D12BufferType::TransferUpload : D3D12BufferType::TransferDownload, - false)); - } - - void D3D12_DestroyGraphicsTransferBuffer(NonNullPtr buffer) - { - DestroyBuffer(reinterpret_cast(buffer.Get())); - } - - void* D3D12_MapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer) - { - auto d3d12Buffer = reinterpret_cast(buffer.Get()); - void* ptr = nullptr; - - // 0-0 range means we don't intend to read anything. - D3D12_RANGE readRange = { 0, 0 }; - if (FAILED(d3d12Buffer->Handle->Map(0, &readRange, &ptr))) - { - return nullptr; - } - return ptr; - } - - void D3D12_UnmapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer) - { - auto d3d12Buffer = reinterpret_cast(buffer.Get()); - d3d12Buffer->Handle->Unmap(0, nullptr); - } - - void* D3D12_MapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer) - { - auto d3d12Buffer = reinterpret_cast(buffer.Get()); - void* ptr = nullptr; - D3D12_RANGE readRange = { 0, 0 }; - if (FAILED(d3d12Buffer->Handle->Map(0, &readRange, &ptr))) - { - return nullptr; - } - return ptr; - } - - void D3D12_UnmapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer) - { - auto d3d12Buffer = reinterpret_cast(buffer.Get()); - d3d12Buffer->Handle->Unmap(0, nullptr); - } - - uint32 GetDescriptorIndex(NonNullPtr /*driver*/, NonNullPtr buffer) - { - auto d3d12Buffer = reinterpret_cast(buffer.Get()); - return d3d12Buffer->Descriptor.Index; - } - - void D3D12_CopyBuffer(NonNullPtr commandList, NonNullPtr dst, - NonNullPtr src, size_t size, size_t dstOffset, size_t srcOffset) - { - auto d3d12CmdList = reinterpret_cast(commandList.Get()); - auto d3d12Dst = reinterpret_cast(dst.Get()); - auto d3d12Src = reinterpret_cast(src.Get()); - - // Transition DST to COPY_DEST if needed - if (d3d12Dst->CurrentState != D3D12_RESOURCE_STATE_COPY_DEST) - { - D3D12_RESOURCE_BARRIER barrier = {}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barrier.Transition.pResource = d3d12Dst->Handle; - barrier.Transition.StateBefore = d3d12Dst->CurrentState; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST; - barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - - d3d12CmdList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier); - d3d12Dst->CurrentState = D3D12_RESOURCE_STATE_COPY_DEST; - } - - // Src is Upload Buffer, usually effectively GenericRead/Common but for Upload heaps it's simpler. - // We assume Upload buffers are always in state GENERIC_READ or similar suitable for CopySrc. - // D3D12 Upload heaps start in GENERIC_READ and cannot transition. - - d3d12CmdList->GraphicsCommandList.CommandList->CopyBufferRegion(d3d12Dst->Handle, dstOffset, - d3d12Src->Handle, srcOffset, size); - } - - void D3D12_TransitionBufferToReadable(NonNullPtr commandList, NonNullPtr buffer) - { - auto d3d12CmdList = reinterpret_cast(commandList.Get()); - auto d3d12Buffer = reinterpret_cast(buffer.Get()); - - D3D12_RESOURCE_STATES neededState = - D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; - - if (d3d12Buffer->CurrentState != neededState) - { - D3D12_RESOURCE_BARRIER barrier = {}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barrier.Transition.pResource = d3d12Buffer->Handle; - barrier.Transition.StateBefore = d3d12Buffer->CurrentState; - barrier.Transition.StateAfter = neededState; - barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - - d3d12CmdList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier); - d3d12Buffer->CurrentState = neededState; - } - } - // End Buffers - - // Begin Fences - void DisposePendingResourcces(NonNullPtr driver) - { - // TODO Destroy anything (buffer, texture, etc...) - uint32 idx = 0; - while (idx < driver->GraphicsPipelinesToDisposeCount) - { - if (driver->GraphicsPipelinesToDispose[idx]->ReferenceCount == 0) - { - ReleaseGraphicsPipeline(driver->GraphicsPipelinesToDispose[idx]); - - driver->GraphicsPipelinesToDispose[idx] = - driver->GraphicsPipelinesToDispose[driver->GraphicsPipelinesToDisposeCount - 1]; - driver->GraphicsPipelinesToDisposeCount -= 1; - } - else - { - idx++; - } - } - } - - void ReleaseFenceToPool(NonNullPtr driver, NonNullPtr fence) - { - Assert(driver->AvailableFenceCount + 1 <= driver->AvailableFenceCapacity); - - driver->AvailableFences[driver->AvailableFenceCount] = fence; - driver->AvailableFenceCount += 1; - - LogDebug(LogCategory::Graphics, "ReleaseFenceToPool %x fence. Handle %x | Event %x | Refcount %d", - fence.Get(), fence->Handle, fence->Event, fence->ReferenceCount); - } - - void D3D12_ReleaseFence(NonNullPtr driver, NonNullPtr fence JULIET_DEBUG_PARAM(String querier)) - { - auto d3d12driver = static_cast(driver.Get()); - auto d3d12Fence = reinterpret_cast(fence.Get()); - -#if JULIET_DEBUG - LogDebug(LogCategory::Graphics, "ReleaseFence | %x fence. Handle %x | Event %x | Refcount %d | Querier %s", - d3d12Fence, d3d12Fence->Handle, d3d12Fence->Event, d3d12Fence->ReferenceCount, CStr(querier)); -#endif - if (--d3d12Fence->ReferenceCount == 0) - { - ReleaseFenceToPool(d3d12driver, d3d12Fence); - } - } - - D3D12Fence* D3D12_AcquireFence(NonNullPtr driver JULIET_DEBUG_PARAM(String querier)) - { - D3D12Fence* fence; - ID3D12Fence* handle; - - // TODO :Thread safe (lock + atomic) - - if (driver->AvailableFenceCount == 0) - { - HRESULT result = driver->D3D12Device->CreateFence(D3D12_FENCE_UNSIGNALED_VALUE, D3D12_FENCE_FLAG_NONE, - IID_ID3D12Fence, reinterpret_cast(&handle)); - if (FAILED(result)) - { - D3D12_LogError(driver->D3D12Device, "Failed to create fence!", result); - return nullptr; - } - - fence = ArenaPushStruct(driver->DriverArena JULIET_DEBUG_PARAM("D3D12Fence")); - if (!fence) - { - handle->Release(); - - return nullptr; - } - fence->Handle = handle; - fence->Event = CreateEvent(nullptr, false, false, nullptr); - fence->ReferenceCount = 0; -#if JULIET_DEBUG - LogDebug(LogCategory::Graphics, "Acquire Querier %s | Setting Signal to 0 NEW fence", CStr(querier)); -#endif - } else { - fence = driver->AvailableFences[driver->AvailableFenceCount - 1]; - driver->AvailableFenceCount -= 1; - fence->Handle->Signal(D3D12_FENCE_UNSIGNALED_VALUE); -#if JULIET_DEBUG - LogDebug(LogCategory::Graphics, "Acquire Querier %s | Setting Signal to 0, RECYCLING", CStr(querier)); -#endif + heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD; + initialState = D3D12_RESOURCE_STATE_GENERIC_READ; } - - fence->ReferenceCount += 1; - Assert(fence->ReferenceCount == 1); - -#if JULIET_DEBUG - LogDebug(LogCategory::Graphics, "Acquire Querier %s | %x fence. Handle %x | Event %x | Refcount %d", - CStr(querier), fence, fence->Handle, fence->Event, fence->ReferenceCount); -#endif - - return fence; + } + else + { + // Must be a static buffer (Base type) + heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT; + initialState = D3D12_RESOURCE_STATE_COMMON; } - bool D3D12_CleanCommandList(NonNullPtr driver, NonNullPtr commandList, bool cancel) + D3D12_RESOURCE_DESC desc = {}; + desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + desc.Alignment = 0; + desc.Width = size; + desc.Height = 1; + desc.DepthOrArraySize = 1; + desc.MipLevels = 1; + desc.Format = DXGI_FORMAT_UNKNOWN; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + desc.Flags = D3D12_RESOURCE_FLAG_NONE; + + Log(LogLevel::Message, LogCategory::Graphics, "CreateBuffer: Device=%p, Size=%zu, Type=%s Use=%s", + (void*)d3d12Driver->D3D12Device, size, D3D12BufferTypeToString(type), BufferUsageToString(usage)); + + ID3D12Resource* handle = nullptr; + HRESULT result = + d3d12Driver->D3D12Device->CreateCommittedResource(&heapProperties, heapFlags, &desc, initialState, nullptr, + IID_ID3D12Resource, reinterpret_cast(&handle)); + + if (FAILED(result)) { - // No more presentation data - commandList->PresentDataCount = 0; + Log(LogLevel::Error, LogCategory::Graphics, "Could not create buffer! HRESULT=0x%08X", static_cast(result)); + Log(LogLevel::Error, LogCategory::Graphics, "Failed Desc: Width=%llu Layout=%d HeapType=%d", + (unsigned long long)desc.Width, (int)desc.Layout, (int)heapProperties.Type); - HRESULT result = commandList->GraphicsCommandList.Allocator->Reset(); - if (FAILED(result)) + HRESULT removeReason = d3d12Driver->D3D12Device->GetDeviceRemovedReason(); + if (FAILED(removeReason)) { - D3D12_LogError(driver->D3D12Device, "Could not reset command allocator", result); - return false; + Log(LogLevel::Error, LogCategory::Graphics, "Device Removed Reason: 0x%08X", static_cast(removeReason)); } - result = commandList->GraphicsCommandList.CommandList->Reset(commandList->GraphicsCommandList.Allocator, nullptr); - if (FAILED(result)) - { - D3D12_LogError(driver->D3D12Device, "Could not reset command list", result); - return false; - } - - if (commandList->Sampler_Heap) [[likely]] - { - D3D12_ReturnSamplerHeapToPool(driver, commandList->Sampler_Heap); - commandList->Sampler_Heap = nullptr; - } - commandList->CRB_SRV_UAV_Heap = nullptr; - - // Clean up resource tracking - for (uint32 idx = 0; idx < commandList->UsedTextureCount; ++idx) - { - --commandList->UsedTextures[idx]->ReferenceCount; - } - commandList->UsedTextureCount = 0; - - for (uint32 idx = 0; idx < commandList->UsedGraphicsPipelineCount; ++idx) - { - --commandList->UsedGraphicsPipelines[idx]->ReferenceCount; - } - commandList->UsedGraphicsPipelineCount = 0; - - // Release Fence if needed - if (commandList->AutoReleaseFence) - { - D3D12_ReleaseFence(driver.Get(), reinterpret_cast(commandList->InFlightFence) - JULIET_DEBUG_PARAM(ConstString("CleanCommandList"))); - commandList->InFlightFence = nullptr; - } - - // Return the command list to the pool - Assert(driver->AvailableCommandListCount + 1 <= driver->AvailableCommandListCapacity); - driver->AvailableCommandLists[driver->AvailableCommandListCount] = commandList; - driver->AvailableCommandListCount += 1; - - // Remove this command list from the submitted list - if (!cancel) - { - for (uint32 idx = 0; idx < driver->SubmittedCommandListCount; idx += 1) - { - if (driver->SubmittedCommandLists[idx] == commandList) - { - driver->SubmittedCommandLists[idx] = driver->SubmittedCommandLists[driver->SubmittedCommandListCount - 1]; - driver->SubmittedCommandListCount -= 1; - break; - } - } - } - - return true; + DestroyBuffer(buffer); + return nullptr; } - bool D3D12_WaitUntilGPUIsIdle(NonNullPtr driver) + buffer->Handle = handle; + buffer->CurrentState = initialState; + buffer->Descriptor.Index = UINT32_MAX; + buffer->Size = size; + + if (usage == BufferUsage::ConstantBuffer || usage == BufferUsage::StructuredBuffer) { - auto d3d12driver = static_cast(driver.Get()); - D3D12Fence* fence = D3D12_AcquireFence(d3d12driver JULIET_DEBUG_PARAM(ConstString("WaitUntilGPUIsIdle"))); - if (!fence) - { - return false; - } + auto& heap = d3d12Driver->BindlessDescriptorHeap; - if (d3d12driver->GraphicsQueue) + D3D12Descriptor descriptor; + if (AssignDescriptor(heap, descriptor)) { - // Insert a signal into the end of the command queue... - d3d12driver->GraphicsQueue->Signal(fence->Handle, D3D12_FENCE_SIGNAL_VALUE); + buffer->Descriptor = descriptor; - // ...and then block on it. - if (fence->Handle->GetCompletedValue() != D3D12_FENCE_SIGNAL_VALUE) + D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = descriptor.CpuHandle; + + if (usage == BufferUsage::ConstantBuffer) { - HRESULT result = fence->Handle->SetEventOnCompletion(D3D12_FENCE_SIGNAL_VALUE, fence->Event); - if (FAILED(result)) - { - D3D12_LogError(d3d12driver->D3D12Device, "Setting fence event failed!", result); - return false; - } - - DWORD waitResult = WaitForSingleObject(fence->Event, INFINITE); - if (waitResult == WAIT_FAILED) - { - D3D12_LogError(d3d12driver->D3D12Device, "Wait failed!", result); - return false; - } + D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; + cbvDesc.BufferLocation = handle->GetGPUVirtualAddress(); + cbvDesc.SizeInBytes = static_cast(size); + d3d12Driver->D3D12Device->CreateConstantBufferView(&cbvDesc, cpuHandle); } - } - - D3D12_ReleaseFence(driver, - reinterpret_cast(fence) JULIET_DEBUG_PARAM(ConstString("WaitUntilGPUIsIdle"))); - - bool result = true; - - // Clean up - { - int32 idx = 0; - while (idx < d3d12driver->SubmittedCommandListCount) + else if (usage == BufferUsage::StructuredBuffer) { - result &= D3D12_CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false); - // CleanCommandList swaps [idx] with last and decrements count. - // Don't increment — re-check the swapped-in element. - } - } + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srvDesc.Buffer.FirstElement = 0; - DisposePendingResourcces(d3d12driver); - - return result; - } - - bool Wait(NonNullPtr driver, bool waitForAll, Fence* const* fences, - uint32 numFences JULIET_DEBUG_PARAM(String querier)) - { - auto d3d12driver = static_cast(driver.Get()); - - TempArena tempArena = ArenaTempBegin(d3d12driver->DriverArena); - - HANDLE* events = - ArenaPushArray(tempArena.Arena, numFences JULIET_DEBUG_PARAM("Wait() HANDLE - JUST IN CASE")); - MemoryZero(events, sizeof(HANDLE) * numFences); - - for (uint32 i = 0; i < numFences; ++i) - { - D3D12Fence* fence = reinterpret_cast(fences[i]); - - HRESULT res = fence->Handle->SetEventOnCompletion(D3D12_FENCE_SIGNAL_VALUE, fence->Event); - if (FAILED(res)) - { - D3D12_LogError(d3d12driver->D3D12Device, "Setting fence event failed!", res); - ArenaTempEnd(tempArena); - return false; - } - - events[i] = fence->Event; - } -#if JULIET_DEBUG - LogDebug(LogCategory::Graphics, "Waiting for %d fences. Querier %s", numFences, CStr(querier)); -#endif - for (uint32 i = 0; i < numFences; ++i) - { - D3D12Fence* d3d12fence = reinterpret_cast(fences[i]); - LogDebug(LogCategory::Graphics, "Waiting for %x fence. Handle %x | Event %x | Refcount %d", d3d12fence, - d3d12fence->Handle, d3d12fence->Event, d3d12fence->ReferenceCount); - } - - DWORD waitResult = WaitForMultipleObjects(numFences, events, waitForAll, INFINITE); - - ArenaTempEnd(tempArena); - - if (waitResult == WAIT_FAILED) - { - Juliet::LogError(LogCategory::Graphics, "Wait failed"); - return false; - } - - bool result = true; - - // Clean up - { - int32 idx = 0; - while (idx < d3d12driver->SubmittedCommandListCount) - { - uint64 fenceValue = d3d12driver->SubmittedCommandLists[idx]->InFlightFence->Handle->GetCompletedValue(); - if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) + if (stride > 0) { - result &= D3D12_CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false); + srvDesc.Format = DXGI_FORMAT_UNKNOWN; + srvDesc.Buffer.NumElements = static_cast(size / stride); + srvDesc.Buffer.StructureByteStride = static_cast(stride); + srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; } else { - idx += 1; + srvDesc.Format = DXGI_FORMAT_R32_TYPELESS; + srvDesc.Buffer.NumElements = static_cast(size / 4); + srvDesc.Buffer.StructureByteStride = 0; + srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW; } + + d3d12Driver->D3D12Device->CreateShaderResourceView(handle, &srvDesc, cpuHandle); + Log(LogLevel::Message, LogCategory::Graphics, " -> SRV DescriptorIndex=%u", descriptor.Index); } } - - DisposePendingResourcces(d3d12driver); - - return result; - } - - bool D3D12_QueryFence(NonNullPtr /*driver*/, NonNullPtr /*fence*/) - { - Unimplemented(); - return true; - } - - void ResourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState, - D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource, uint32 subresourceIndex, - bool needsUavBarrier) - { - D3D12_RESOURCE_BARRIER barrierDesc[2]; - uint32 numBarriers = 0; - - // No transition barrier is needed if the state is not changing. - if (sourceState != destinationState) - { - barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrierDesc[numBarriers].Flags = static_cast(0); - barrierDesc[numBarriers].Transition.StateBefore = sourceState; - barrierDesc[numBarriers].Transition.StateAfter = destinationState; - barrierDesc[numBarriers].Transition.pResource = resource; - barrierDesc[numBarriers].Transition.Subresource = subresourceIndex; - - numBarriers += 1; - } - - if (needsUavBarrier) - { - barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; - barrierDesc[numBarriers].Flags = static_cast(0); - barrierDesc[numBarriers].UAV.pResource = resource; - - numBarriers += 1; - } - - if (numBarriers > 0) - { - commandList->GraphicsCommandList.CommandList->ResourceBarrier(numBarriers, barrierDesc); - } - } - - void DestroyFence(NonNullPtr fence) - { - if (fence->Handle) - { - fence->Handle->Release(); - } - - if (fence->Event) - { - CloseHandle(fence->Event); - } - } - // End Fences - - // Begin Swapchain - bool CreateSwapChainTexture(NonNullPtr driver, NonNullPtr swapChain, - SwapChainComposition composition, NonNullPtr textureContainer, uint8 index) - { - ID3D12Resource* swapChainTexture = nullptr; - HRESULT result = swapChain->GetBuffer(index, IID_ID3D12Resource, reinterpret_cast(&swapChainTexture)); - if (FAILED(result)) - { - D3D12_LogError(driver->D3D12Device, "Cannot get buffer from SwapChain", result); - return false; - } - - auto texture = static_cast(Calloc(1, sizeof(D3D12Texture))); - if (!texture) - { - D3D12_LogError(driver->D3D12Device, "Cannot allocate D3D12Texture (out of memory)", result); - swapChainTexture->Release(); - return false; - } - - texture->ReferenceCount += 1; - texture->SubresourceCount = 1; - texture->Subresources = static_cast(Calloc(1, sizeof(D3D12TextureSubresource))); - if (!texture->Subresources) - { - D3D12_LogError(driver->D3D12Device, "Cannot allocate D3D12TextureSubresource (out of memory)", result); - Free(texture); - swapChainTexture->Release(); - return false; - } - texture->Subresources[0].RTVHandles = - static_cast(Calloc(1, sizeof(D3D12StagingDescriptor))); - texture->Subresources[0].UAVHandle.Heap = nullptr; - texture->Subresources[0].UAVHandle.Heap = nullptr; - texture->Subresources[0].Parent = texture; - texture->Subresources[0].Index = 0; - texture->Subresources[0].Layer = 0; - texture->Subresources[0].Depth = 1; - texture->Subresources[0].Level = 0; - - D3D12_RESOURCE_DESC textureDesc = swapChainTexture->GetDesc(); - textureContainer->Header.CreateInfo.Width = static_cast(textureDesc.Width); - textureContainer->Header.CreateInfo.Height = static_cast(textureDesc.Height); - textureContainer->Header.CreateInfo.LayerCount = 1; - textureContainer->Header.CreateInfo.MipLevelCount = 1; - textureContainer->Header.CreateInfo.Type = TextureType::Texture_2D; - textureContainer->Header.CreateInfo.Flags = TextureUsageFlag::ColorTarget; - textureContainer->Header.CreateInfo.SampleCount = TextureSampleCount::One; - textureContainer->Header.CreateInfo.Format = SwapchainCompositionToJulietTextureFormat[ToUnderlying(composition)]; - - textureContainer->Textures = static_cast(Calloc(1, sizeof(D3D12Texture*))); - if (!textureContainer->Textures) - { - Free(texture->Subresources); - Free(texture); - swapChainTexture->Release(); - return false; - } - - textureContainer->Capacity = 1; - textureContainer->Count = 1; - textureContainer->Textures[0] = texture; - textureContainer->ActiveTexture = texture; - textureContainer->CanBeCycled = false; - - texture->Container = textureContainer; - texture->IndexInContainer = 0; - - // Assign RTV to the swapchain texture - DXGI_FORMAT swapchainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)]; - AssignStagingDescriptor(driver, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, texture->Subresources[0].RTVHandles[0]); - D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = (composition == SwapChainComposition::SDR_LINEAR) ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : swapchainFormat; - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = 0; - rtvDesc.Texture2D.PlaneSlice = 0; - - driver->D3D12Device->CreateRenderTargetView(swapChainTexture, &rtvDesc, - texture->Subresources[0].RTVHandles[0].CpuHandle); - - swapChainTexture->Release(); - - return true; - } - - bool D3D12_AcquireSwapChainTexture(bool block, NonNullPtr commandList, NonNullPtr window, - Texture** swapchainTexture) - { - auto d3d12CommandList = reinterpret_cast(commandList.Get()); - - auto* driver = d3d12CommandList->Driver; - Assert(driver->WindowData); - - // TODO: Find a way to fetch window data more smoothly from the window ptr - // In the mean time i will just void it or the variable is unused and cause a warning - (void)window; - auto* windowData = driver->WindowData; - Assert(windowData->Window == window.Get()); - - if (windowData->InFlightFences[windowData->WindowFrameCounter] != nullptr) - { - if (block) - { - // Wait until the fence for the frame is signaled. - // In VSYNC this means waiting that the least recent presented frame is done - if (!Wait(driver, true, &windowData->InFlightFences[windowData->WindowFrameCounter], - 1 JULIET_DEBUG_PARAM(ConstString("AcquireSwapChainTexture")))) - { - return false; - } - } - else - { - // If work is not done, the least recent fence wont be signaled. - // In that case we return true to notify that there is no error, but rendering should be skipped as their will be no swapchainTexture - if (!D3D12_QueryFence(driver, windowData->InFlightFences[windowData->WindowFrameCounter])) - { - return true; - } - } - - D3D12_ReleaseFence(driver, windowData->InFlightFences[windowData->WindowFrameCounter] JULIET_DEBUG_PARAM( - ConstString("AcquireSwapChainTexture"))); - windowData->InFlightFences[windowData->WindowFrameCounter] = nullptr; - } - - uint32 swapchainIndex = windowData->SwapChain->GetCurrentBackBufferIndex(); - HRESULT result = windowData->SwapChain->GetBuffer( - swapchainIndex, IID_ID3D12Resource, - reinterpret_cast(&windowData->SwapChainTextureContainers[swapchainIndex].ActiveTexture->Resource)); - if (FAILED(result)) - { - D3D12_LogError(driver->D3D12Device, "Could not acquire swapchain", result); - return false; - } - - // When the swap chain texture is acquired it's time to present - Assert(d3d12CommandList->PresentDataCount + 1 <= d3d12CommandList->PresentDataCapacity); - d3d12CommandList->PresentDatas[d3d12CommandList->PresentDataCount].WindowData = windowData; - d3d12CommandList->PresentDatas[d3d12CommandList->PresentDataCount].SwapChainImageIndex = swapchainIndex; - d3d12CommandList->PresentDataCount += 1; - - // Create the presentation barrier. - D3D12_RESOURCE_BARRIER barrierDesc; - barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrierDesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; - barrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; - barrierDesc.Transition.pResource = windowData->SwapChainTextureContainers[swapchainIndex].ActiveTexture->Resource; - barrierDesc.Transition.Subresource = 0; - - d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrierDesc); - - *swapchainTexture = reinterpret_cast(&windowData->SwapChainTextureContainers[swapchainIndex]); - - return true; - } - - bool CreateSwapChain(NonNullPtr driver, NonNullPtr windowData, - SwapChainComposition composition, PresentMode presentMode) - { - auto windowWin32State = static_cast(windowData->Window->State); - HWND windowHandle = windowWin32State->Handle; - if (!IsWindow(windowHandle)) - { - Assert(false, "windowWin32State->Handle is not a window handle ???"); - return false; - } - - // TODO: I have no way to test HDR easily except the steamdeck - DXGI_FORMAT swapChainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)]; - - windowData->SwapChainTextureCount = std::clamp(driver->FramesInFlight, 2, 3); - - DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; - swapChainDesc.Width = 0; // Use the whole width - swapChainDesc.Height = 0; // Use the whole height - swapChainDesc.Format = swapChainFormat; - swapChainDesc.Stereo = 0; - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.SampleDesc.Quality = 0; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapChainDesc.BufferCount = windowData->SwapChainTextureCount; - swapChainDesc.Scaling = DXGI_SCALING_STRETCH; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; - if (driver->IsTearingSupported) - { - swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; - } else { - swapChainDesc.Flags = 0; + LogError(LogCategory::Graphics, "Bindless Heap Full or Invalid!"); } + } - DXGI_SWAP_CHAIN_FULLSCREEN_DESC swapChainFullscreenDesc = {}; - swapChainFullscreenDesc.RefreshRate.Numerator = 0; - swapChainFullscreenDesc.RefreshRate.Denominator = 0; - swapChainFullscreenDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; - swapChainFullscreenDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - swapChainFullscreenDesc.Windowed = true; + return buffer; + } - IDXGISwapChain1* swapChain = nullptr; - HRESULT result = driver->DXGIFactory->CreateSwapChainForHwnd(static_cast(driver->GraphicsQueue), - windowHandle, &swapChainDesc, - &swapChainFullscreenDesc, nullptr, &swapChain); - if (FAILED(result)) + GraphicsBuffer* D3D12_CreateGraphicsBuffer(NonNullPtr driver, size_t size, size_t stride, BufferUsage usage, bool isDynamic) + { + auto d3d12Driver = static_cast(driver.Get()); + return reinterpret_cast(CreateBuffer(d3d12Driver, size, stride, usage, D3D12BufferType::Base, isDynamic)); + } + + void D3D12_DestroyGraphicsBuffer(NonNullPtr buffer) + { + DestroyBuffer(reinterpret_cast(buffer.Get())); + } + + GraphicsTransferBuffer* D3D12_CreateGraphicsTransferBuffer(NonNullPtr driver, size_t size, TransferBufferUsage usage) + { + auto d3d12Driver = static_cast(driver.Get()); + return reinterpret_cast( + CreateBuffer(d3d12Driver, size, 0, BufferUsage::None, + usage == TransferBufferUsage::Upload ? D3D12BufferType::TransferUpload : D3D12BufferType::TransferDownload, + false)); + } + + void D3D12_DestroyGraphicsTransferBuffer(NonNullPtr buffer) + { + DestroyBuffer(reinterpret_cast(buffer.Get())); + } + + void* D3D12_MapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer) + { + auto d3d12Buffer = reinterpret_cast(buffer.Get()); + void* ptr = nullptr; + + // 0-0 range means we don't intend to read anything. + D3D12_RANGE readRange = { 0, 0 }; + if (FAILED(d3d12Buffer->Handle->Map(0, &readRange, &ptr))) + { + return nullptr; + } + return ptr; + } + + void D3D12_UnmapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer) + { + auto d3d12Buffer = reinterpret_cast(buffer.Get()); + d3d12Buffer->Handle->Unmap(0, nullptr); + } + + void* D3D12_MapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer) + { + auto d3d12Buffer = reinterpret_cast(buffer.Get()); + void* ptr = nullptr; + D3D12_RANGE readRange = { 0, 0 }; + if (FAILED(d3d12Buffer->Handle->Map(0, &readRange, &ptr))) + { + return nullptr; + } + return ptr; + } + + void D3D12_UnmapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer) + { + auto d3d12Buffer = reinterpret_cast(buffer.Get()); + d3d12Buffer->Handle->Unmap(0, nullptr); + } + + uint32 GetDescriptorIndex(NonNullPtr /*driver*/, NonNullPtr buffer) + { + auto d3d12Buffer = reinterpret_cast(buffer.Get()); + return d3d12Buffer->Descriptor.Index; + } + + void D3D12_CopyBuffer(NonNullPtr commandList, NonNullPtr dst, + NonNullPtr src, size_t size, size_t dstOffset, size_t srcOffset) + { + auto d3d12CmdList = reinterpret_cast(commandList.Get()); + auto d3d12Dst = reinterpret_cast(dst.Get()); + auto d3d12Src = reinterpret_cast(src.Get()); + + // Transition DST to COPY_DEST if needed + if (d3d12Dst->CurrentState != D3D12_RESOURCE_STATE_COPY_DEST) + { + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrier.Transition.pResource = d3d12Dst->Handle; + barrier.Transition.StateBefore = d3d12Dst->CurrentState; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + + d3d12CmdList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier); + d3d12Dst->CurrentState = D3D12_RESOURCE_STATE_COPY_DEST; + } + + // Src is Upload Buffer, usually effectively GenericRead/Common but for Upload heaps it's simpler. + // We assume Upload buffers are always in state GENERIC_READ or similar suitable for CopySrc. + // D3D12 Upload heaps start in GENERIC_READ and cannot transition. + + d3d12CmdList->GraphicsCommandList.CommandList->CopyBufferRegion(d3d12Dst->Handle, dstOffset, d3d12Src->Handle, + srcOffset, size); + } + + void D3D12_TransitionBufferToReadable(NonNullPtr commandList, NonNullPtr buffer) + { + auto d3d12CmdList = reinterpret_cast(commandList.Get()); + auto d3d12Buffer = reinterpret_cast(buffer.Get()); + + D3D12_RESOURCE_STATES neededState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + + if (d3d12Buffer->CurrentState != neededState) + { + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrier.Transition.pResource = d3d12Buffer->Handle; + barrier.Transition.StateBefore = d3d12Buffer->CurrentState; + barrier.Transition.StateAfter = neededState; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + + d3d12CmdList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier); + d3d12Buffer->CurrentState = neededState; + } + } + // End Buffers + + // Begin Fences + void DisposePendingResourcces(NonNullPtr driver) + { + // TODO Destroy anything (buffer, texture, etc...) + uint32 idx = 0; + while (idx < driver->GraphicsPipelinesToDisposeCount) + { + if (driver->GraphicsPipelinesToDispose[idx]->ReferenceCount == 0) { - D3D12_LogError(driver->D3D12Device, "Failed to create SwapChain", result); - return false; - } + ReleaseGraphicsPipeline(driver->GraphicsPipelinesToDispose[idx]); - IDXGISwapChain3* swapChain3 = nullptr; - result = swapChain->QueryInterface(IID_IDXGISwapChain3, reinterpret_cast(&swapChain3)); - swapChain->Release(); - if (FAILED(result)) - { - D3D12_LogError(driver->D3D12Device, "Could not query IDXGISwapChain3 interface", result); - return false; - } - - if (composition != SwapChainComposition::SDR) - { - swapChain3->SetColorSpace1(SwapchainCompositionToColorSpace[ToUnderlying(composition)]); - } - - IDXGIFactory1* parentFactory = nullptr; - result = swapChain3->GetParent(IID_IDXGIFactory1, reinterpret_cast(&parentFactory)); - if (FAILED(result)) - { - Log(LogLevel::Warning, LogCategory::Graphics, "Cannot get SwapChain Parent! Error Code: " HRESULT_FMT, result); + driver->GraphicsPipelinesToDispose[idx] = + driver->GraphicsPipelinesToDispose[driver->GraphicsPipelinesToDisposeCount - 1]; + driver->GraphicsPipelinesToDisposeCount -= 1; } else { - // Disable DXGI window crap - result = parentFactory->MakeWindowAssociation(windowHandle, DXGI_MWA_NO_WINDOW_CHANGES); - if (FAILED(result)) - { - Log(LogLevel::Warning, LogCategory::Graphics, "MakeWindowAssociation failed! Error Code: " HRESULT_FMT, result); - } - parentFactory->Release(); + idx++; } + } + } - swapChain3->GetDesc1(&swapChainDesc); + void ReleaseFenceToPool(NonNullPtr driver, NonNullPtr fence) + { + Assert(driver->AvailableFenceCount + 1 <= driver->AvailableFenceCapacity); + + driver->AvailableFences[driver->AvailableFenceCount] = fence; + driver->AvailableFenceCount += 1; + + LogDebug(LogCategory::Graphics, "ReleaseFenceToPool %x fence. Handle %x | Event %x | Refcount %d", fence.Get(), + fence->Handle, fence->Event, fence->ReferenceCount); + } + + void D3D12_ReleaseFence(NonNullPtr driver, NonNullPtr fence JULIET_DEBUG_PARAM(String querier)) + { + auto d3d12driver = static_cast(driver.Get()); + auto d3d12Fence = reinterpret_cast(fence.Get()); + +#if JULIET_DEBUG + LogDebug(LogCategory::Graphics, "ReleaseFence | %x fence. Handle %x | Event %x | Refcount %d | Querier %s", + d3d12Fence, d3d12Fence->Handle, d3d12Fence->Event, d3d12Fence->ReferenceCount, CStr(querier)); +#endif + if (--d3d12Fence->ReferenceCount == 0) + { + ReleaseFenceToPool(d3d12driver, d3d12Fence); + } + } + + D3D12Fence* D3D12_AcquireFence(NonNullPtr driver JULIET_DEBUG_PARAM(String querier)) + { + D3D12Fence* fence; + ID3D12Fence* handle; + + // TODO :Thread safe (lock + atomic) + + if (driver->AvailableFenceCount == 0) + { + HRESULT result = driver->D3D12Device->CreateFence(D3D12_FENCE_UNSIGNALED_VALUE, D3D12_FENCE_FLAG_NONE, + IID_ID3D12Fence, reinterpret_cast(&handle)); if (FAILED(result)) { - D3D12_LogError(driver->D3D12Device, "Failed to retrieve SwapChain descriptor", result); - return false; - } - windowData->SwapChain = swapChain3; - windowData->SwapChainColorSpace = SwapchainCompositionToColorSpace[ToUnderlying(composition)]; - windowData->SwapChainComposition = composition; - windowData->WindowFrameCounter = 0; - windowData->Width = swapChainDesc.Width; - windowData->Height = swapChainDesc.Height; - windowData->PresentMode = presentMode; - - for (uint8 idx = 0; idx < windowData->SwapChainTextureCount; ++idx) - { - if (!CreateSwapChainTexture(driver, swapChain3, composition, &windowData->SwapChainTextureContainers[idx], idx)) - { - swapChain3->Release(); - return false; - } - } - - return true; - } - - void DestroySwapChain(NonNullPtr driver, NonNullPtr windowData) - { - for (uint32 idx = 0; idx < windowData->SwapChainTextureCount; ++idx) - { - ReleaseStagingDescriptor(driver, - windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles[0]); - - Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles); - Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources); - Free(windowData->SwapChainTextureContainers[idx].ActiveTexture); - Free(windowData->SwapChainTextureContainers[idx].Textures); - } - - windowData->SwapChain->Release(); - windowData->SwapChain = nullptr; - } - - bool D3D12_AcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture) - { - return D3D12_AcquireSwapChainTexture(false, commandList, window, swapChainTexture); - } - - bool D3D12_WaitAndAcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture) - { - return D3D12_AcquireSwapChainTexture(true, commandList, window, swapChainTexture); - } - - bool D3D12_WaitForSwapchain(NonNullPtr driver, NonNullPtr /*window*/) - { - auto* d3d12Driver = static_cast(driver.Get()); - auto* windowData = d3d12Driver->WindowData; - if (!windowData) - { - Juliet::LogError(LogCategory::Graphics, "Cannot wait for swapchain. Window has no Swapchain"); - return false; - } - - if (windowData->InFlightFences[windowData->WindowFrameCounter] != nullptr) - { - if (!Wait(d3d12Driver, true, &windowData->InFlightFences[windowData->WindowFrameCounter], - 1 JULIET_DEBUG_PARAM(ConstString("WaitForSwapchain")))) - { - return false; - } - } - - return true; - } - - TextureFormat D3D12_GetSwapChainTextureFormat(NonNullPtr driver, [[maybe_unused]] NonNullPtr window) - { - auto* d3d12Driver = static_cast(driver.Get()); - - auto* windowData = d3d12Driver->WindowData; - if (!windowData) - { - Juliet::LogError(LogCategory::Graphics, "Cannot get swapchain format. Window has no Swapchain"); - return TextureFormat::Invalid; - } - - Assert(windowData->Window == window.Get()); - return windowData->SwapChainTextureContainers[windowData->WindowFrameCounter].Header.CreateInfo.Format; - } - // End Swapchain - - // Begin Texture - - uint32 ComputeSubresourceIndex(uint32 mipLevel, uint32 layer, uint32 numLevels) - { - return mipLevel + (layer * numLevels); - } - - D3D12_RESOURCE_STATES GetDefaultTextureResourceState(TextureUsageFlag usageFlags) - { - if ((usageFlags & TextureUsageFlag::Sampler) != TextureUsageFlag::None) - { - return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; - } - if ((usageFlags & TextureUsageFlag::GraphicsStorageRead) != TextureUsageFlag::None) - { - return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; - } - if ((usageFlags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None) - { - return D3D12_RESOURCE_STATE_RENDER_TARGET; - } - if ((usageFlags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None) - { - return D3D12_RESOURCE_STATE_DEPTH_WRITE; - } - if ((usageFlags & TextureUsageFlag::ComputeStorageRead) != TextureUsageFlag::None) - { - return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; - } - if ((usageFlags & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None) - { - return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; - } - if ((usageFlags & TextureUsageFlag::ComputeStorageSimultaneousReadWrite) != TextureUsageFlag::None) - { - return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; - } - Log(LogLevel::Error, LogCategory::Graphics, "Texture has no default usage mode!"); - return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; - } - - D3D12TextureSubresource* FetchTextureSubresource(NonNullPtr container, uint32 layer, uint32 level) - { - uint32 index = ComputeSubresourceIndex(level, layer, container->Header.CreateInfo.MipLevelCount); - return &container->ActiveTexture->Subresources[index]; - } - - void TextureSubresourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState, - D3D12_RESOURCE_STATES destinationState, NonNullPtr textureSubresource) - { - TextureUsageFlag currentFlag = textureSubresource->Parent->Container->Header.CreateInfo.Flags; - bool needsUAVBarrier = - ((currentFlag & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None) || - ((currentFlag & TextureUsageFlag::ComputeStorageSimultaneousReadWrite) != TextureUsageFlag::None); - ResourceBarrier(commandList, sourceState, destinationState, textureSubresource->Parent->Resource, - textureSubresource->Index, needsUAVBarrier); - } - - void TextureSubresourceTransitionFromDefaultUsage(NonNullPtr commandList, - NonNullPtr subresource, - D3D12_RESOURCE_STATES toTextureUsage) - { - D3D12_RESOURCE_STATES defaultUsage = - GetDefaultTextureResourceState(subresource->Parent->Container->Header.CreateInfo.Flags); - TextureSubresourceBarrier(commandList, defaultUsage, toTextureUsage, subresource); - } - - void TextureTransitionFromDefaultUsage(NonNullPtr commandList, - NonNullPtr texture, D3D12_RESOURCE_STATES toTextureUsage) - { - for (uint32 i = 0; i < texture->SubresourceCount; ++i) - { - TextureSubresourceTransitionFromDefaultUsage(commandList, &texture->Subresources[i], toTextureUsage); - } - } - - void TextureSubresourceTransitionToDefaultUsage(NonNullPtr commandList, - NonNullPtr subresource, - D3D12_RESOURCE_STATES fromTextureUsage) - { - D3D12_RESOURCE_STATES defaultUsage = - GetDefaultTextureResourceState(subresource->Parent->Container->Header.CreateInfo.Flags); - TextureSubresourceBarrier(commandList, fromTextureUsage, defaultUsage, subresource); - } - - void TextureTransitionToDefaultUsage(NonNullPtr commandList, NonNullPtr texture, - D3D12_RESOURCE_STATES fromTextureUsage) - { - for (uint32 i = 0; i < texture->SubresourceCount; ++i) - { - TextureSubresourceTransitionToDefaultUsage(commandList, &texture->Subresources[i], fromTextureUsage); - } - } - - D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr commandList, - NonNullPtr container, - uint32 layer, uint32 level, bool shouldCycle, - D3D12_RESOURCE_STATES newTextureUsage) - { - D3D12TextureSubresource* subresource = FetchTextureSubresource(container, layer, level); - if (shouldCycle and container->CanBeCycled and subresource->Parent->ReferenceCount > 0) - { - // TODO: Cycle the active texture to an available one. Not needed for swap chain (current objective) - // CycleActiveTexture(commandList->Driver, container); - - subresource = FetchTextureSubresource(container, layer, level); - } - - TextureSubresourceTransitionFromDefaultUsage(commandList, subresource, newTextureUsage); - - return subresource; - } - - Texture* D3D12_CreateTexture(NonNullPtr driver, const TextureCreateInfo& createInfo) - { - auto* d3d12Driver = static_cast(driver.Get()); - - D3D12_RESOURCE_DESC desc = {}; - switch (createInfo.Type) - { - case TextureType::Texture_2D: - case TextureType::Texture_2DArray: - case TextureType::Texture_Cube: - case TextureType::Texture_CubeArray: desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; break; - case TextureType::Texture_3D: - case TextureType::Texture_3DArray: desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D; break; - } - - desc.Alignment = 0; - desc.Width = createInfo.Width; - desc.Height = createInfo.Height; - desc.DepthOrArraySize = static_cast(createInfo.LayerCount); - desc.MipLevels = static_cast(createInfo.MipLevelCount); - desc.Format = ConvertToD3D12TextureFormat(createInfo.Format); - desc.SampleDesc.Count = JulietToD3D12_SampleCount[ToUnderlying(createInfo.SampleCount)]; - desc.SampleDesc.Quality = 0; - desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; - desc.Flags = D3D12_RESOURCE_FLAG_NONE; - - if ((createInfo.Flags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None) - { - desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; - } - if ((createInfo.Flags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None) - { - desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; - } - if ((createInfo.Flags & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None) - { - desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - } - - D3D12_HEAP_PROPERTIES heapProps = {}; - heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 0; // We don't do multi-adapter operation - heapProps.VisibleNodeMask = 0; // We don't do multi-adapter operation - - ID3D12Resource* resource = nullptr; - D3D12_CLEAR_VALUE clearValue = {}; - D3D12_CLEAR_VALUE* pClearValue = nullptr; - - if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) - { - clearValue.Format = ConvertToD3D12DepthFormat(createInfo.Format); - clearValue.DepthStencil.Depth = 1.0f; - clearValue.DepthStencil.Stencil = 0; - pClearValue = &clearValue; - } - else if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) - { - clearValue.Format = desc.Format; - clearValue.Color[0] = 0.0f; - clearValue.Color[1] = 0.0f; - clearValue.Color[2] = 0.0f; - clearValue.Color[3] = 0.0f; - pClearValue = &clearValue; - } - - D3D12_RESOURCE_STATES initialState = GetDefaultTextureResourceState(createInfo.Flags); - HRESULT hr = d3d12Driver->D3D12Device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &desc, - initialState, pClearValue, IID_ID3D12Resource, - reinterpret_cast(&resource)); - - if (FAILED(hr)) - { - D3D12_LogError(d3d12Driver->D3D12Device, "Failed to create D3D12 committed resource for texture", hr); + D3D12_LogError(driver->D3D12Device, "Failed to create fence!", result); return nullptr; } - auto* textureContainer = static_cast(Calloc(1, sizeof(D3D12TextureContainer))); - auto* texture = static_cast(Calloc(1, sizeof(D3D12Texture))); - - textureContainer->Header.CreateInfo = createInfo; - textureContainer->ActiveTexture = texture; - textureContainer->Textures = static_cast(Malloc(sizeof(D3D12Texture*))); - textureContainer->Textures[0] = texture; - textureContainer->Capacity = 1; - textureContainer->Count = 1; - textureContainer->CanBeCycled = true; - - texture->Container = textureContainer; - texture->Resource = resource; - texture->ReferenceCount = 1; - - uint32 numLayers = std::max(1, createInfo.LayerCount); - uint32 numMips = std::max(1, createInfo.MipLevelCount); - texture->SubresourceCount = numLayers * numMips; - texture->Subresources = - static_cast(Calloc(texture->SubresourceCount, sizeof(D3D12TextureSubresource))); - - for (uint32 layer = 0; layer < numLayers; ++layer) + fence = ArenaPushStruct(driver->DriverArena JULIET_DEBUG_PARAM("D3D12Fence")); + if (!fence) { - for (uint32 mip = 0; mip < numMips; ++mip) + handle->Release(); + + return nullptr; + } + fence->Handle = handle; + fence->Event = CreateEvent(nullptr, false, false, nullptr); + fence->ReferenceCount = 0; +#if JULIET_DEBUG + LogDebug(LogCategory::Graphics, "Acquire Querier %s | Setting Signal to 0 NEW fence", CStr(querier)); +#endif + } + else + { + fence = driver->AvailableFences[driver->AvailableFenceCount - 1]; + driver->AvailableFenceCount -= 1; + fence->Handle->Signal(D3D12_FENCE_UNSIGNALED_VALUE); +#if JULIET_DEBUG + LogDebug(LogCategory::Graphics, "Acquire Querier %s | Setting Signal to 0, RECYCLING", CStr(querier)); +#endif + } + + fence->ReferenceCount += 1; + Assert(fence->ReferenceCount == 1); + +#if JULIET_DEBUG + LogDebug(LogCategory::Graphics, "Acquire Querier %s | %x fence. Handle %x | Event %x | Refcount %d", + CStr(querier), fence, fence->Handle, fence->Event, fence->ReferenceCount); +#endif + + return fence; + } + + bool D3D12_CleanCommandList(NonNullPtr driver, NonNullPtr commandList, bool cancel) + { + // No more presentation data + commandList->PresentDataCount = 0; + + HRESULT result = commandList->GraphicsCommandList.Allocator->Reset(); + if (FAILED(result)) + { + D3D12_LogError(driver->D3D12Device, "Could not reset command allocator", result); + return false; + } + + result = commandList->GraphicsCommandList.CommandList->Reset(commandList->GraphicsCommandList.Allocator, nullptr); + if (FAILED(result)) + { + D3D12_LogError(driver->D3D12Device, "Could not reset command list", result); + return false; + } + + if (commandList->Sampler_Heap) [[likely]] + { + D3D12_ReturnSamplerHeapToPool(driver, commandList->Sampler_Heap); + commandList->Sampler_Heap = nullptr; + } + commandList->CRB_SRV_UAV_Heap = nullptr; + + // Clean up resource tracking + for (uint32 idx = 0; idx < commandList->UsedTextureCount; ++idx) + { + --commandList->UsedTextures[idx]->ReferenceCount; + } + commandList->UsedTextureCount = 0; + + for (uint32 idx = 0; idx < commandList->UsedGraphicsPipelineCount; ++idx) + { + --commandList->UsedGraphicsPipelines[idx]->ReferenceCount; + } + commandList->UsedGraphicsPipelineCount = 0; + + // Release Fence if needed + if (commandList->AutoReleaseFence) + { + D3D12_ReleaseFence(driver.Get(), reinterpret_cast(commandList->InFlightFence) + JULIET_DEBUG_PARAM(ConstString("CleanCommandList"))); + commandList->InFlightFence = nullptr; + } + + // Return the command list to the pool + Assert(driver->AvailableCommandListCount + 1 <= driver->AvailableCommandListCapacity); + driver->AvailableCommandLists[driver->AvailableCommandListCount] = commandList; + driver->AvailableCommandListCount += 1; + + // Remove this command list from the submitted list + if (!cancel) + { + for (uint32 idx = 0; idx < driver->SubmittedCommandListCount; idx += 1) + { + if (driver->SubmittedCommandLists[idx] == commandList) { - uint32 index = mip + (layer * numMips); - auto& sub = texture->Subresources[index]; - sub.Parent = texture; - sub.Layer = layer; - sub.Level = mip; - sub.Index = index; - sub.Depth = 1; // 3D texture depth handling would go here - - if ((createInfo.Flags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None) - { - sub.RTVHandles = static_cast(Calloc(1, sizeof(D3D12StagingDescriptor))); - AssignStagingDescriptor(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, sub.RTVHandles[0]); - - D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {}; - rtvDesc.Format = desc.Format; - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = mip; - d3d12Driver->D3D12Device->CreateRenderTargetView(resource, &rtvDesc, sub.RTVHandles[0].CpuHandle); - } - - if ((createInfo.Flags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None) - { - AssignStagingDescriptor(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, sub.DSVHandle); - - D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; - dsvDesc.Format = ConvertToD3D12DepthFormat(createInfo.Format); - dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; - dsvDesc.Texture2D.MipSlice = mip; - d3d12Driver->D3D12Device->CreateDepthStencilView(resource, &dsvDesc, sub.DSVHandle.CpuHandle); - } + driver->SubmittedCommandLists[idx] = driver->SubmittedCommandLists[driver->SubmittedCommandListCount - 1]; + driver->SubmittedCommandListCount -= 1; + break; } } + } - // Create SRV for sampled/readable textures (bindless access) - // Assign to the bindless CBV_SRV_UAV heap + return true; + } + + bool D3D12_WaitUntilGPUIsIdle(NonNullPtr driver) + { + auto d3d12driver = static_cast(driver.Get()); + D3D12Fence* fence = D3D12_AcquireFence(d3d12driver JULIET_DEBUG_PARAM(ConstString("WaitUntilGPUIsIdle"))); + if (!fence) + { + return false; + } + + if (d3d12driver->GraphicsQueue) + { + // Insert a signal into the end of the command queue... + d3d12driver->GraphicsQueue->Signal(fence->Handle, D3D12_FENCE_SIGNAL_VALUE); + + // ...and then block on it. + if (fence->Handle->GetCompletedValue() != D3D12_FENCE_SIGNAL_VALUE) { - D3D12Descriptor descriptor; - if (AssignDescriptor(d3d12Driver->BindlessDescriptorHeap, descriptor)) + HRESULT result = fence->Handle->SetEventOnCompletion(D3D12_FENCE_SIGNAL_VALUE, fence->Event); + if (FAILED(result)) { - texture->SRVHandle = D3D12StagingDescriptor{}; - texture->SRVHandle.CpuHandleIndex = descriptor.Index; - texture->SRVHandle.CpuHandle = descriptor.CpuHandle; - texture->SRVHandle.Heap = descriptor.Heap; - - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.Format = desc.Format; - - // Fix SRV format for Depth Buffers (TypeLess -> Typed) - if (createInfo.Format == TextureFormat::D32_FLOAT) - { - srvDesc.Format = DXGI_FORMAT_R32_FLOAT; - } - else if (createInfo.Format == TextureFormat::D16_UNORM) - { - srvDesc.Format = DXGI_FORMAT_R16_UNORM; - } - else if (createInfo.Format == TextureFormat::D24_UNORM_S8_UINT) - { - srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; - } - else if (createInfo.Format == TextureFormat::D32_FLOAT_S8_UINT) - { - srvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; - } - - srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MostDetailedMip = 0; - srvDesc.Texture2D.MipLevels = numMips; - srvDesc.Texture2D.PlaneSlice = 0; - srvDesc.Texture2D.ResourceMinLODClamp = 0.0f; - - d3d12Driver->D3D12Device->CreateShaderResourceView(resource, &srvDesc, descriptor.CpuHandle); + D3D12_LogError(d3d12driver->D3D12Device, "Setting fence event failed!", result); + return false; } - } - return reinterpret_cast(textureContainer); - } - - void D3D12_DestroyTexture(NonNullPtr driver, NonNullPtr texture) - { - auto* d3d12Driver = static_cast(driver.Get()); - auto* textureContainer = reinterpret_cast(texture.Get()); - - for (uint32 i = 0; i < textureContainer->Count; ++i) - { - D3D12Texture* d3d12Texture = textureContainer->Textures[i]; - for (uint32 j = 0; j < d3d12Texture->SubresourceCount; ++j) + DWORD waitResult = WaitForSingleObject(fence->Event, INFINITE); + if (waitResult == WAIT_FAILED) { - D3D12TextureSubresource& sub = d3d12Texture->Subresources[j]; - if (sub.RTVHandles) - { - ReleaseStagingDescriptor(d3d12Driver, sub.RTVHandles[0]); - Free(sub.RTVHandles); - } - if (sub.DSVHandle.Heap) - { - ReleaseStagingDescriptor(d3d12Driver, sub.DSVHandle); - } - } - d3d12Texture->Resource->Release(); - Free(d3d12Texture->Subresources); - Free(d3d12Texture); - } - - Free(textureContainer->Textures); - Free(textureContainer); - } - // End Texture - - // Begin Command list - index_t GetNewCommandListID() - { - return CommandListID++; - } - - bool HasD3D12CommandListForQueueType(NonNullPtr commandList, QueueType queueType) - { - switch (queueType) - { - case QueueType::Graphics: return commandList->GraphicsCommandList.CommandList != nullptr; - case QueueType::Compute: return commandList->ComputeCommandList.CommandList != nullptr; - case QueueType::Copy: return commandList->CopyCommandList.CommandList != nullptr; - default: return false; - } - } - - void DestroyCommandList(NonNullPtr commandList) - { - // TODO : Handle other kind of command list (copy compute) - if (commandList->GraphicsCommandList.CommandList) - { - commandList->GraphicsCommandList.CommandList->Release(); - } - - commandList->GraphicsCommandList.Allocator->Release(); - } - - bool CreateAllocator(NonNullPtr driver, NonNullPtr baseData, - D3D12_COMMAND_QUEUE_DESC queueDesc) - { - HRESULT result = driver->D3D12Device->CreateCommandAllocator(queueDesc.Type, IID_ID3D12CommandAllocator, - reinterpret_cast(&baseData->Allocator)); - if (FAILED(result)) - { - AssertHR(result, "Cannot create ID3D12CommandAllocator"); - return false; - } - - baseData->Allocator->Reset(); - return true; - } - - bool CreateD3D12CommandListForQueueType(NonNullPtr driver, NonNullPtr commandList, QueueType queueType) - { - // TODO: String library - std::wstring wide_str = L"CommandList ID:" + std::to_wstring(commandList->ID); - - // TODO: Factorize this. Flemme - - // Get Proper allocator for the frame. Reset all allocators and the command list with current frame allocator - auto& queueDesc = driver->QueueDesc[ToUnderlying(queueType)]; - switch (queueType) - { - case QueueType::Graphics: - { - CreateAllocator(driver, &commandList->GraphicsCommandList, queueDesc); - ID3D12GraphicsCommandList6* d3d12GraphicsCommandList = nullptr; - HRESULT result = - driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type, - D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList6, - reinterpret_cast(&d3d12GraphicsCommandList)); - if (FAILED(result)) - { - Assert(false, "Error not implemented: cannot create ID3D12GraphicsCommandList6 (graphics or " - "compute command list"); - return false; - } - - commandList->GraphicsCommandList.CommandList = d3d12GraphicsCommandList; - d3d12GraphicsCommandList->SetName(wide_str.c_str()); - d3d12GraphicsCommandList->Reset(commandList->GraphicsCommandList.Allocator, nullptr); - - return true; - } - case QueueType::Compute: - { - CreateAllocator(driver, &commandList->ComputeCommandList, queueDesc); - ID3D12GraphicsCommandList6* d3d12GraphicsCommandList = nullptr; - HRESULT result = - driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type, - D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList6, - reinterpret_cast(&d3d12GraphicsCommandList)); - if (FAILED(result)) - { - Assert(false, "Error not implemented: cannot create ID3D12GraphicsCommandList6 (graphics or " - "compute command list"); - return false; - } - - commandList->ComputeCommandList.CommandList = d3d12GraphicsCommandList; - d3d12GraphicsCommandList->SetName(wide_str.c_str()); - d3d12GraphicsCommandList->Reset(commandList->ComputeCommandList.Allocator, nullptr); - - return true; - } - case QueueType::Copy: - { - CreateAllocator(driver, &commandList->CopyCommandList, queueDesc); - ID3D12GraphicsCommandList* d3d12CopyCommandList = nullptr; - HRESULT result = - driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type, - D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList, - reinterpret_cast(&d3d12CopyCommandList)); - - if (FAILED(result)) - { - AssertHR(result, "cannot create ID3D12GraphicsCommandList (copy command list)"); - return false; - } - commandList->CopyCommandList.CommandList = d3d12CopyCommandList; - d3d12CopyCommandList->SetName(wide_str.c_str()); - d3d12CopyCommandList->Reset(commandList->CopyCommandList.Allocator, nullptr); - - return true; - } - default: return false; - } - } - - bool AllocateCommandList(NonNullPtr driver, QueueType queueType) - { - if (driver->AvailableCommandLists == nullptr) - { - driver->AvailableCommandLists = - ArenaPushArray(driver->DriverArena, - kMaxCommandListCount JULIET_DEBUG_PARAM("Command list count {}", - kMaxCommandListCount)); - driver->AvailableCommandListCapacity = kMaxCommandListCount; - } - const index_t id = GetNewCommandListID(); - - auto* commandList = - ArenaPushStruct(driver->DriverArena JULIET_DEBUG_PARAM("D3D12CommandList [{}]", id)); - if (!commandList) - { - Log(LogLevel::Error, LogCategory::Graphics, "Cannot allocate D3D12CommandList: Out of memory"); - DestroyCommandList(commandList); - return false; - } - - driver->AvailableCommandLists[driver->AvailableCommandListCount] = commandList; - driver->AvailableCommandListCount += 1; - - commandList->ID = id; - commandList->Driver = driver; - - // Window Handling - commandList->PresentDataCapacity = kMaxPresentDataPerCommandList; - commandList->PresentDataCount = 0; - commandList->PresentDatas = ArenaPushArray( - driver->DriverArena, - kMaxPresentDataPerCommandList JULIET_DEBUG_PARAM("Command list [{}] D3D12PresentData ptr array count " - "{}", - id, kMaxPresentDataPerCommandList)); - - // Resource tracking - commandList->UsedTextureCapacity = kMaxTexturePerCommandList; - commandList->UsedTextureCount = 0; - commandList->UsedTextures = ArenaPushArray( - driver->DriverArena, kMaxTexturePerCommandList JULIET_DEBUG_PARAM("Command list [{}] D3D12Texture " - "ptr array count " - "{}", - id, kMaxTexturePerCommandList)); - - commandList->UsedGraphicsPipelineCapacity = kMaxGraphicsPipelinePerCommandList; - commandList->UsedGraphicsPipelineCount = 0; - commandList->UsedGraphicsPipelines = ArenaPushArray( - driver->DriverArena, - kMaxTexturePerCommandList JULIET_DEBUG_PARAM("Command list [{}] D3D12GraphicsPipeline ptr array count " - "{}", - id, kMaxTexturePerCommandList)); - - // TODO : Simplify this - if (!HasD3D12CommandListForQueueType(commandList, queueType)) - { - if (!CreateD3D12CommandListForQueueType(driver, commandList, queueType)) - { - Log(LogLevel::Error, LogCategory::Graphics, "Cannot Create D3D12 command list"); - DestroyCommandList(commandList); + D3D12_LogError(d3d12driver->D3D12Device, "Wait failed!", result); return false; } } - - return true; } - D3D12CommandList* AcquireCommandListFromPool(NonNullPtr driver, QueueType queueType) + D3D12_ReleaseFence(driver, + reinterpret_cast(fence) JULIET_DEBUG_PARAM(ConstString("WaitUntilGPUIsIdle"))); + + bool result = true; + + // Clean up { - if (driver->AvailableCommandListCount == 0) + int32 idx = 0; + while (idx < d3d12driver->SubmittedCommandListCount) { - if (!AllocateCommandList(driver, queueType)) + result &= D3D12_CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false); + // CleanCommandList swaps [idx] with last and decrements count. + // Don't increment — re-check the swapped-in element. + } + } + + DisposePendingResourcces(d3d12driver); + + return result; + } + + bool Wait(NonNullPtr driver, bool waitForAll, Fence* const* fences, uint32 numFences JULIET_DEBUG_PARAM(String querier)) + { + auto d3d12driver = static_cast(driver.Get()); + + TempArena tempArena = ArenaTempBegin(d3d12driver->DriverArena); + + HANDLE* events = + ArenaPushArray(tempArena.Arena, numFences JULIET_DEBUG_PARAM("Wait() HANDLE - JUST IN CASE")); + MemoryZero(events, sizeof(HANDLE) * numFences); + + for (uint32 i = 0; i < numFences; ++i) + { + D3D12Fence* fence = reinterpret_cast(fences[i]); + + HRESULT res = fence->Handle->SetEventOnCompletion(D3D12_FENCE_SIGNAL_VALUE, fence->Event); + if (FAILED(res)) + { + D3D12_LogError(d3d12driver->D3D12Device, "Setting fence event failed!", res); + ArenaTempEnd(tempArena); + return false; + } + + events[i] = fence->Event; + } +#if JULIET_DEBUG + LogDebug(LogCategory::Graphics, "Waiting for %d fences. Querier %s", numFences, CStr(querier)); +#endif + for (uint32 i = 0; i < numFences; ++i) + { + D3D12Fence* d3d12fence = reinterpret_cast(fences[i]); + LogDebug(LogCategory::Graphics, "Waiting for %x fence. Handle %x | Event %x | Refcount %d", d3d12fence, + d3d12fence->Handle, d3d12fence->Event, d3d12fence->ReferenceCount); + } + + DWORD waitResult = WaitForMultipleObjects(numFences, events, waitForAll, INFINITE); + + ArenaTempEnd(tempArena); + + if (waitResult == WAIT_FAILED) + { + LogError(LogCategory::Graphics, "Wait failed"); + return false; + } + + bool result = true; + + // Clean up + { + int32 idx = 0; + while (idx < d3d12driver->SubmittedCommandListCount) + { + uint64 fenceValue = d3d12driver->SubmittedCommandLists[idx]->InFlightFence->Handle->GetCompletedValue(); + if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) { - return nullptr; + result &= D3D12_CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false); + } + else + { + idx += 1; } } - - D3D12CommandList* commandList = driver->AvailableCommandLists[driver->AvailableCommandListCount - 1]; - driver->AvailableCommandListCount -= 1; - - return commandList; } - CommandList* D3D12_AcquireCommandList(NonNullPtr driver, QueueType queueType) + DisposePendingResourcces(d3d12driver); + + return result; + } + + bool D3D12_QueryFence(NonNullPtr /*driver*/, NonNullPtr /*fence*/) + { + Unimplemented(); + return true; + } + + void ResourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState, + D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource, uint32 subresourceIndex, bool needsUavBarrier) + { + D3D12_RESOURCE_BARRIER barrierDesc[2]; + uint32 numBarriers = 0; + + // No transition barrier is needed if the state is not changing. + if (sourceState != destinationState) { - auto* d3d12Driver = static_cast(driver.Get()); + barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrierDesc[numBarriers].Flags = static_cast(0); + barrierDesc[numBarriers].Transition.StateBefore = sourceState; + barrierDesc[numBarriers].Transition.StateAfter = destinationState; + barrierDesc[numBarriers].Transition.pResource = resource; + barrierDesc[numBarriers].Transition.Subresource = subresourceIndex; - D3D12CommandList* commandList = AcquireCommandListFromPool(d3d12Driver, queueType); - - commandList->AutoReleaseFence = true; - - return reinterpret_cast(commandList); + numBarriers += 1; } - void D3D12_SetViewPort(NonNullPtr commandList, const GraphicsViewPort& viewPort) + if (needsUavBarrier) { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; + barrierDesc[numBarriers].Flags = static_cast(0); + barrierDesc[numBarriers].UAV.pResource = resource; - D3D12_VIEWPORT d3d12Viewport; - d3d12Viewport.TopLeftX = viewPort.X; - d3d12Viewport.TopLeftY = viewPort.Y; - d3d12Viewport.Width = viewPort.Width; - d3d12Viewport.Height = viewPort.Height; - d3d12Viewport.MinDepth = viewPort.MinDepth; - d3d12Viewport.MaxDepth = viewPort.MaxDepth; - d3d12CommandList->GraphicsCommandList.CommandList->RSSetViewports(1, &d3d12Viewport); + numBarriers += 1; } - void D3D12_SetScissorRect(NonNullPtr commandList, const Rectangle& rectangle) + if (numBarriers > 0) { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - D3D12_RECT scissorRect; - scissorRect.left = rectangle.X; - scissorRect.top = rectangle.Y; - scissorRect.right = rectangle.X + rectangle.Width; - scissorRect.bottom = rectangle.Y + rectangle.Height; - d3d12CommandList->GraphicsCommandList.CommandList->RSSetScissorRects(1, &scissorRect); + commandList->GraphicsCommandList.CommandList->ResourceBarrier(numBarriers, barrierDesc); + } + } + + void DestroyFence(NonNullPtr fence) + { + if (fence->Handle) + { + fence->Handle->Release(); } - void D3D12_SetBlendConstants(NonNullPtr commandList, FColor blendConstants) + if (fence->Event) { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - FLOAT blendFactor[4] = { blendConstants.R, blendConstants.G, blendConstants.B, blendConstants.A }; - d3d12CommandList->GraphicsCommandList.CommandList->OMSetBlendFactor(blendFactor); + CloseHandle(fence->Event); + } + } + // End Fences + + // Begin Swapchain + bool CreateSwapChainTexture(NonNullPtr driver, NonNullPtr swapChain, + SwapChainComposition composition, NonNullPtr textureContainer, uint8 index) + { + ID3D12Resource* swapChainTexture = nullptr; + HRESULT result = swapChain->GetBuffer(index, IID_ID3D12Resource, reinterpret_cast(&swapChainTexture)); + if (FAILED(result)) + { + D3D12_LogError(driver->D3D12Device, "Cannot get buffer from SwapChain", result); + return false; } - void D3D12_SetStencilReference(NonNullPtr commandList, uint8 reference) + auto texture = static_cast(Calloc(1, sizeof(D3D12Texture))); + if (!texture) { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - d3d12CommandList->GraphicsCommandList.CommandList->OMSetStencilRef(reference); + D3D12_LogError(driver->D3D12Device, "Cannot allocate D3D12Texture (out of memory)", result); + swapChainTexture->Release(); + return false; } - void D3D12_SetIndexBuffer(NonNullPtr commandList, NonNullPtr buffer, - IndexFormat format, size_t indexCount, index_t offset) + texture->ReferenceCount += 1; + texture->SubresourceCount = 1; + texture->Subresources = static_cast(Calloc(1, sizeof(D3D12TextureSubresource))); + if (!texture->Subresources) { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - auto* d3d12Buffer = reinterpret_cast(buffer.Get()); + D3D12_LogError(driver->D3D12Device, "Cannot allocate D3D12TextureSubresource (out of memory)", result); + Free(texture); + swapChainTexture->Release(); + return false; + } + texture->Subresources[0].RTVHandles = static_cast(Calloc(1, sizeof(D3D12StagingDescriptor))); + texture->Subresources[0].UAVHandle.Heap = nullptr; + texture->Subresources[0].UAVHandle.Heap = nullptr; + texture->Subresources[0].Parent = texture; + texture->Subresources[0].Index = 0; + texture->Subresources[0].Layer = 0; + texture->Subresources[0].Depth = 1; + texture->Subresources[0].Level = 0; - // Transition to INDEX_BUFFER state if needed - if (d3d12Buffer->CurrentState != D3D12_RESOURCE_STATE_GENERIC_READ) + D3D12_RESOURCE_DESC textureDesc = swapChainTexture->GetDesc(); + textureContainer->Header.CreateInfo.Width = static_cast(textureDesc.Width); + textureContainer->Header.CreateInfo.Height = static_cast(textureDesc.Height); + textureContainer->Header.CreateInfo.LayerCount = 1; + textureContainer->Header.CreateInfo.MipLevelCount = 1; + textureContainer->Header.CreateInfo.Type = TextureType::Texture_2D; + textureContainer->Header.CreateInfo.Flags = TextureUsageFlag::ColorTarget; + textureContainer->Header.CreateInfo.SampleCount = TextureSampleCount::One; + textureContainer->Header.CreateInfo.Format = SwapchainCompositionToJulietTextureFormat[ToUnderlying(composition)]; + + textureContainer->Textures = static_cast(Calloc(1, sizeof(D3D12Texture*))); + if (!textureContainer->Textures) + { + Free(texture->Subresources); + Free(texture); + swapChainTexture->Release(); + return false; + } + + textureContainer->Capacity = 1; + textureContainer->Count = 1; + textureContainer->Textures[0] = texture; + textureContainer->ActiveTexture = texture; + textureContainer->CanBeCycled = false; + + texture->Container = textureContainer; + texture->IndexInContainer = 0; + + // Assign RTV to the swapchain texture + DXGI_FORMAT swapchainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)]; + AssignStagingDescriptor(driver, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, texture->Subresources[0].RTVHandles[0]); + D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = (composition == SwapChainComposition::SDR_LINEAR) ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : swapchainFormat; + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = 0; + rtvDesc.Texture2D.PlaneSlice = 0; + + driver->D3D12Device->CreateRenderTargetView(swapChainTexture, &rtvDesc, texture->Subresources[0].RTVHandles[0].CpuHandle); + + swapChainTexture->Release(); + + return true; + } + + bool D3D12_AcquireSwapChainTexture(bool block, NonNullPtr commandList, NonNullPtr window, Texture** swapchainTexture) + { + auto d3d12CommandList = reinterpret_cast(commandList.Get()); + + auto* driver = d3d12CommandList->Driver; + Assert(driver->WindowData); + + // TODO: Find a way to fetch window data more smoothly from the window ptr + // In the mean time i will just void it or the variable is unused and cause a warning + (void)window; + auto* windowData = driver->WindowData; + Assert(windowData->Window == window.Get()); + + if (windowData->InFlightFences[windowData->WindowFrameCounter] != nullptr) + { + if (block) { - D3D12_RESOURCE_BARRIER barrier = {}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barrier.Transition.pResource = d3d12Buffer->Handle; - barrier.Transition.StateBefore = d3d12Buffer->CurrentState; - barrier.Transition.StateAfter = - D3D12_RESOURCE_STATE_GENERIC_READ; // Since we use a mega buffer we use the generic read that includes D3D12_RESOURCE_STATE_INDEX_BUFFER - barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - - d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier); - d3d12Buffer->CurrentState = D3D12_RESOURCE_STATE_GENERIC_READ; - } - - D3D12_INDEX_BUFFER_VIEW ibView; - ibView.BufferLocation = d3d12Buffer->Handle->GetGPUVirtualAddress() + offset; - if (format == IndexFormat::UInt16) - { - ibView.SizeInBytes = static_cast(indexCount * sizeof(uint16)); - ibView.Format = DXGI_FORMAT_R16_UINT; + // Wait until the fence for the frame is signaled. + // In VSYNC this means waiting that the least recent presented frame is done + if (!Wait(driver, true, &windowData->InFlightFences[windowData->WindowFrameCounter], + 1 JULIET_DEBUG_PARAM(ConstString("AcquireSwapChainTexture")))) + { + return false; + } } else { - ibView.SizeInBytes = static_cast(indexCount * sizeof(uint32)); - ibView.Format = DXGI_FORMAT_R32_UINT; + // If work is not done, the least recent fence wont be signaled. + // In that case we return true to notify that there is no error, but rendering should be skipped as their will be no swapchainTexture + if (!D3D12_QueryFence(driver, windowData->InFlightFences[windowData->WindowFrameCounter])) + { + return true; + } } - d3d12CommandList->GraphicsCommandList.CommandList->IASetIndexBuffer(&ibView); + D3D12_ReleaseFence(driver, windowData->InFlightFences[windowData->WindowFrameCounter] JULIET_DEBUG_PARAM( + ConstString("AcquireSwapChainTexture"))); + windowData->InFlightFences[windowData->WindowFrameCounter] = nullptr; } - void D3D12_SetPushConstants(NonNullPtr commandList, ShaderStage /*stage*/, - uint32 rootParameterIndex, uint32 numConstants, const void* constants) + uint32 swapchainIndex = windowData->SwapChain->GetCurrentBackBufferIndex(); + HRESULT result = windowData->SwapChain->GetBuffer( + swapchainIndex, IID_ID3D12Resource, + reinterpret_cast(&windowData->SwapChainTextureContainers[swapchainIndex].ActiveTexture->Resource)); + if (FAILED(result)) { - auto d3d12CommandList = reinterpret_cast(commandList.Get()); - // For now we assume Graphics Root Signature. Compute support would need a check or separate function. - d3d12CommandList->GraphicsCommandList.CommandList->SetGraphicsRoot32BitConstants(rootParameterIndex, - numConstants, constants, 0); + D3D12_LogError(driver->D3D12Device, "Could not acquire swapchain", result); + return false; } - void SetDescriptorHeaps(NonNullPtr commandList) + // When the swap chain texture is acquired it's time to present + Assert(d3d12CommandList->PresentDataCount + 1 <= d3d12CommandList->PresentDataCapacity); + d3d12CommandList->PresentDatas[d3d12CommandList->PresentDataCount].WindowData = windowData; + d3d12CommandList->PresentDatas[d3d12CommandList->PresentDataCount].SwapChainImageIndex = swapchainIndex; + d3d12CommandList->PresentDataCount += 1; + + // Create the presentation barrier. + D3D12_RESOURCE_BARRIER barrierDesc; + barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrierDesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; + barrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; + barrierDesc.Transition.pResource = windowData->SwapChainTextureContainers[swapchainIndex].ActiveTexture->Resource; + barrierDesc.Transition.Subresource = 0; + + d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrierDesc); + + *swapchainTexture = reinterpret_cast(&windowData->SwapChainTextureContainers[swapchainIndex]); + + return true; + } + + bool CreateSwapChain(NonNullPtr driver, NonNullPtr windowData, + SwapChainComposition composition, PresentMode presentMode) + { + auto windowWin32State = static_cast(windowData->Window->State); + HWND windowHandle = windowWin32State->Handle; + if (!IsWindow(windowHandle)) { - ID3D12DescriptorHeap* heaps[2]; - D3D12DescriptorHeap* viewHeap = nullptr; - D3D12DescriptorHeap* samplerHeap = nullptr; - - viewHeap = commandList->Driver->BindlessDescriptorHeap; - - samplerHeap = AcquireSamplerHeapFromPool(commandList->Driver); - - commandList->CRB_SRV_UAV_Heap = viewHeap; - commandList->Sampler_Heap = samplerHeap; - - heaps[0] = viewHeap->Handle; - heaps[1] = samplerHeap->Handle; - - commandList->GraphicsCommandList.CommandList->SetDescriptorHeaps(2, heaps); + Assert(false, "windowWin32State->Handle is not a window handle ???"); + return false; } + // TODO: I have no way to test HDR easily except the steamdeck + DXGI_FORMAT swapChainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)]; + + windowData->SwapChainTextureCount = std::clamp(driver->FramesInFlight, 2, 3); + + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; + swapChainDesc.Width = 0; // Use the whole width + swapChainDesc.Height = 0; // Use the whole height + swapChainDesc.Format = swapChainFormat; + swapChainDesc.Stereo = 0; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapChainDesc.BufferCount = windowData->SwapChainTextureCount; + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; + if (driver->IsTearingSupported) + { + swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + } + else + { + swapChainDesc.Flags = 0; + } + + DXGI_SWAP_CHAIN_FULLSCREEN_DESC swapChainFullscreenDesc = {}; + swapChainFullscreenDesc.RefreshRate.Numerator = 0; + swapChainFullscreenDesc.RefreshRate.Denominator = 0; + swapChainFullscreenDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + swapChainFullscreenDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + swapChainFullscreenDesc.Windowed = true; + + IDXGISwapChain1* swapChain = nullptr; + HRESULT result = + driver->DXGIFactory->CreateSwapChainForHwnd(static_cast(driver->GraphicsQueue), windowHandle, + &swapChainDesc, &swapChainFullscreenDesc, nullptr, &swapChain); + if (FAILED(result)) + { + D3D12_LogError(driver->D3D12Device, "Failed to create SwapChain", result); + return false; + } + + IDXGISwapChain3* swapChain3 = nullptr; + result = swapChain->QueryInterface(IID_IDXGISwapChain3, reinterpret_cast(&swapChain3)); + swapChain->Release(); + if (FAILED(result)) + { + D3D12_LogError(driver->D3D12Device, "Could not query IDXGISwapChain3 interface", result); + return false; + } + + if (composition != SwapChainComposition::SDR) + { + swapChain3->SetColorSpace1(SwapchainCompositionToColorSpace[ToUnderlying(composition)]); + } + + IDXGIFactory1* parentFactory = nullptr; + result = swapChain3->GetParent(IID_IDXGIFactory1, reinterpret_cast(&parentFactory)); + if (FAILED(result)) + { + Log(LogLevel::Warning, LogCategory::Graphics, "Cannot get SwapChain Parent! Error Code: " HRESULT_FMT, result); + } + else + { + // Disable DXGI window crap + result = parentFactory->MakeWindowAssociation(windowHandle, DXGI_MWA_NO_WINDOW_CHANGES); + if (FAILED(result)) + { + Log(LogLevel::Warning, LogCategory::Graphics, "MakeWindowAssociation failed! Error Code: " HRESULT_FMT, result); + } + parentFactory->Release(); + } + + swapChain3->GetDesc1(&swapChainDesc); + if (FAILED(result)) + { + D3D12_LogError(driver->D3D12Device, "Failed to retrieve SwapChain descriptor", result); + return false; + } + windowData->SwapChain = swapChain3; + windowData->SwapChainColorSpace = SwapchainCompositionToColorSpace[ToUnderlying(composition)]; + windowData->SwapChainComposition = composition; + windowData->WindowFrameCounter = 0; + windowData->Width = swapChainDesc.Width; + windowData->Height = swapChainDesc.Height; + windowData->PresentMode = presentMode; + + for (uint8 idx = 0; idx < windowData->SwapChainTextureCount; ++idx) + { + if (!CreateSwapChainTexture(driver, swapChain3, composition, &windowData->SwapChainTextureContainers[idx], idx)) + { + swapChain3->Release(); + return false; + } + } + + return true; + } + + void DestroySwapChain(NonNullPtr driver, NonNullPtr windowData) + { + for (uint32 idx = 0; idx < windowData->SwapChainTextureCount; ++idx) + { + ReleaseStagingDescriptor(driver, windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles[0]); + + Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles); + Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources); + Free(windowData->SwapChainTextureContainers[idx].ActiveTexture); + Free(windowData->SwapChainTextureContainers[idx].Textures); + } + + windowData->SwapChain->Release(); + windowData->SwapChain = nullptr; + } + + bool D3D12_AcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture) + { + return D3D12_AcquireSwapChainTexture(false, commandList, window, swapChainTexture); + } + + bool D3D12_WaitAndAcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture) + { + return D3D12_AcquireSwapChainTexture(true, commandList, window, swapChainTexture); + } + + bool D3D12_WaitForSwapchain(NonNullPtr driver, NonNullPtr /*window*/) + { + auto* d3d12Driver = static_cast(driver.Get()); + auto* windowData = d3d12Driver->WindowData; + if (!windowData) + { + LogError(LogCategory::Graphics, "Cannot wait for swapchain. Window has no Swapchain"); + return false; + } + + if (windowData->InFlightFences[windowData->WindowFrameCounter] != nullptr) + { + if (!Wait(d3d12Driver, true, &windowData->InFlightFences[windowData->WindowFrameCounter], + 1 JULIET_DEBUG_PARAM(ConstString("WaitForSwapchain")))) + { + return false; + } + } + + return true; + } + + TextureFormat D3D12_GetSwapChainTextureFormat(NonNullPtr driver, [[maybe_unused]] NonNullPtr window) + { + auto* d3d12Driver = static_cast(driver.Get()); + + auto* windowData = d3d12Driver->WindowData; + if (!windowData) + { + LogError(LogCategory::Graphics, "Cannot get swapchain format. Window has no Swapchain"); + return TextureFormat::Invalid; + } + + Assert(windowData->Window == window.Get()); + return windowData->SwapChainTextureContainers[windowData->WindowFrameCounter].Header.CreateInfo.Format; + } + // End Swapchain + + // Begin Texture + + uint32 ComputeSubresourceIndex(uint32 mipLevel, uint32 layer, uint32 numLevels) + { + return mipLevel + (layer * numLevels); + } + + D3D12_RESOURCE_STATES GetDefaultTextureResourceState(TextureUsageFlag usageFlags) + { + if ((usageFlags & TextureUsageFlag::Sampler) != TextureUsageFlag::None) + { + return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; + } + if ((usageFlags & TextureUsageFlag::GraphicsStorageRead) != TextureUsageFlag::None) + { + return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; + } + if ((usageFlags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None) + { + return D3D12_RESOURCE_STATE_RENDER_TARGET; + } + if ((usageFlags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None) + { + return D3D12_RESOURCE_STATE_DEPTH_WRITE; + } + if ((usageFlags & TextureUsageFlag::ComputeStorageRead) != TextureUsageFlag::None) + { + return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + } + if ((usageFlags & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None) + { + return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + } + if ((usageFlags & TextureUsageFlag::ComputeStorageSimultaneousReadWrite) != TextureUsageFlag::None) + { + return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + } + Log(LogLevel::Error, LogCategory::Graphics, "Texture has no default usage mode!"); + return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; + } + + D3D12TextureSubresource* FetchTextureSubresource(NonNullPtr container, uint32 layer, uint32 level) + { + uint32 index = ComputeSubresourceIndex(level, layer, container->Header.CreateInfo.MipLevelCount); + return &container->ActiveTexture->Subresources[index]; + } + + void TextureSubresourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState, + D3D12_RESOURCE_STATES destinationState, NonNullPtr textureSubresource) + { + TextureUsageFlag currentFlag = textureSubresource->Parent->Container->Header.CreateInfo.Flags; + bool needsUAVBarrier = ((currentFlag & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None) || + ((currentFlag & TextureUsageFlag::ComputeStorageSimultaneousReadWrite) != TextureUsageFlag::None); + ResourceBarrier(commandList, sourceState, destinationState, textureSubresource->Parent->Resource, + textureSubresource->Index, needsUAVBarrier); + } + + void TextureSubresourceTransitionFromDefaultUsage(NonNullPtr commandList, + NonNullPtr subresource, + D3D12_RESOURCE_STATES toTextureUsage) + { + D3D12_RESOURCE_STATES defaultUsage = + GetDefaultTextureResourceState(subresource->Parent->Container->Header.CreateInfo.Flags); + TextureSubresourceBarrier(commandList, defaultUsage, toTextureUsage, subresource); + } + + void TextureTransitionFromDefaultUsage(NonNullPtr commandList, NonNullPtr texture, + D3D12_RESOURCE_STATES toTextureUsage) + { + for (uint32 i = 0; i < texture->SubresourceCount; ++i) + { + TextureSubresourceTransitionFromDefaultUsage(commandList, &texture->Subresources[i], toTextureUsage); + } + } + + void TextureSubresourceTransitionToDefaultUsage(NonNullPtr commandList, + NonNullPtr subresource, D3D12_RESOURCE_STATES fromTextureUsage) + { + D3D12_RESOURCE_STATES defaultUsage = + GetDefaultTextureResourceState(subresource->Parent->Container->Header.CreateInfo.Flags); + TextureSubresourceBarrier(commandList, fromTextureUsage, defaultUsage, subresource); + } + + void TextureTransitionToDefaultUsage(NonNullPtr commandList, NonNullPtr texture, + D3D12_RESOURCE_STATES fromTextureUsage) + { + for (uint32 i = 0; i < texture->SubresourceCount; ++i) + { + TextureSubresourceTransitionToDefaultUsage(commandList, &texture->Subresources[i], fromTextureUsage); + } + } + + D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr commandList, + NonNullPtr container, uint32 layer, + uint32 level, bool shouldCycle, D3D12_RESOURCE_STATES newTextureUsage) + { + D3D12TextureSubresource* subresource = FetchTextureSubresource(container, layer, level); + if (shouldCycle and container->CanBeCycled and subresource->Parent->ReferenceCount > 0) + { + // TODO: Cycle the active texture to an available one. Not needed for swap chain (current objective) + // CycleActiveTexture(commandList->Driver, container); + + subresource = FetchTextureSubresource(container, layer, level); + } + + TextureSubresourceTransitionFromDefaultUsage(commandList, subresource, newTextureUsage); + + return subresource; + } + + Texture* D3D12_CreateTexture(NonNullPtr driver, const TextureCreateInfo& createInfo) + { + auto* d3d12Driver = static_cast(driver.Get()); + + D3D12_RESOURCE_DESC desc = {}; + switch (createInfo.Type) + { + case TextureType::Texture_2D: + case TextureType::Texture_2DArray: + case TextureType::Texture_Cube: + case TextureType::Texture_CubeArray: desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; break; + case TextureType::Texture_3D: + case TextureType::Texture_3DArray: desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D; break; + } + + desc.Alignment = 0; + desc.Width = createInfo.Width; + desc.Height = createInfo.Height; + desc.DepthOrArraySize = static_cast(createInfo.LayerCount); + desc.MipLevels = static_cast(createInfo.MipLevelCount); + desc.Format = ConvertToD3D12TextureFormat(createInfo.Format); + desc.SampleDesc.Count = JulietToD3D12_SampleCount[ToUnderlying(createInfo.SampleCount)]; + desc.SampleDesc.Quality = 0; + desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + desc.Flags = D3D12_RESOURCE_FLAG_NONE; + + if ((createInfo.Flags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None) + { + desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + } + if ((createInfo.Flags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None) + { + desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; + } + if ((createInfo.Flags & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None) + { + desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + } + + D3D12_HEAP_PROPERTIES heapProps = {}; + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + heapProps.CreationNodeMask = 0; // We don't do multi-adapter operation + heapProps.VisibleNodeMask = 0; // We don't do multi-adapter operation + + ID3D12Resource* resource = nullptr; + D3D12_CLEAR_VALUE clearValue = {}; + D3D12_CLEAR_VALUE* pClearValue = nullptr; + + if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) + { + clearValue.Format = ConvertToD3D12DepthFormat(createInfo.Format); + clearValue.DepthStencil.Depth = 1.0f; + clearValue.DepthStencil.Stencil = 0; + pClearValue = &clearValue; + } + else if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) + { + clearValue.Format = desc.Format; + clearValue.Color[0] = 0.0f; + clearValue.Color[1] = 0.0f; + clearValue.Color[2] = 0.0f; + clearValue.Color[3] = 0.0f; + pClearValue = &clearValue; + } + + D3D12_RESOURCE_STATES initialState = GetDefaultTextureResourceState(createInfo.Flags); + HRESULT hr = d3d12Driver->D3D12Device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &desc, + initialState, pClearValue, IID_ID3D12Resource, + reinterpret_cast(&resource)); + + if (FAILED(hr)) + { + D3D12_LogError(d3d12Driver->D3D12Device, "Failed to create D3D12 committed resource for texture", hr); + return nullptr; + } + + auto* textureContainer = static_cast(Calloc(1, sizeof(D3D12TextureContainer))); + auto* texture = static_cast(Calloc(1, sizeof(D3D12Texture))); + + textureContainer->Header.CreateInfo = createInfo; + textureContainer->ActiveTexture = texture; + textureContainer->Textures = static_cast(Malloc(sizeof(D3D12Texture*))); + textureContainer->Textures[0] = texture; + textureContainer->Capacity = 1; + textureContainer->Count = 1; + textureContainer->CanBeCycled = true; + + texture->Container = textureContainer; + texture->Resource = resource; + texture->ReferenceCount = 1; + + uint32 numLayers = std::max(1, createInfo.LayerCount); + uint32 numMips = std::max(1, createInfo.MipLevelCount); + texture->SubresourceCount = numLayers * numMips; + texture->Subresources = + static_cast(Calloc(texture->SubresourceCount, sizeof(D3D12TextureSubresource))); + + for (uint32 layer = 0; layer < numLayers; ++layer) + { + for (uint32 mip = 0; mip < numMips; ++mip) + { + uint32 index = mip + (layer * numMips); + auto& sub = texture->Subresources[index]; + sub.Parent = texture; + sub.Layer = layer; + sub.Level = mip; + sub.Index = index; + sub.Depth = 1; // 3D texture depth handling would go here + + if ((createInfo.Flags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None) + { + sub.RTVHandles = static_cast(Calloc(1, sizeof(D3D12StagingDescriptor))); + AssignStagingDescriptor(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, sub.RTVHandles[0]); + + D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {}; + rtvDesc.Format = desc.Format; + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mip; + d3d12Driver->D3D12Device->CreateRenderTargetView(resource, &rtvDesc, sub.RTVHandles[0].CpuHandle); + } + + if ((createInfo.Flags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None) + { + AssignStagingDescriptor(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, sub.DSVHandle); + + D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; + dsvDesc.Format = ConvertToD3D12DepthFormat(createInfo.Format); + dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; + dsvDesc.Texture2D.MipSlice = mip; + d3d12Driver->D3D12Device->CreateDepthStencilView(resource, &dsvDesc, sub.DSVHandle.CpuHandle); + } + } + } + + // Create SRV for sampled/readable textures (bindless access) + // Assign to the bindless CBV_SRV_UAV heap + { + D3D12Descriptor descriptor; + if (AssignDescriptor(d3d12Driver->BindlessDescriptorHeap, descriptor)) + { + texture->SRVHandle = D3D12StagingDescriptor{}; + texture->SRVHandle.CpuHandleIndex = descriptor.Index; + texture->SRVHandle.CpuHandle = descriptor.CpuHandle; + texture->SRVHandle.Heap = descriptor.Heap; + + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.Format = desc.Format; + + // Fix SRV format for Depth Buffers (TypeLess -> Typed) + if (createInfo.Format == TextureFormat::D32_FLOAT) + { + srvDesc.Format = DXGI_FORMAT_R32_FLOAT; + } + else if (createInfo.Format == TextureFormat::D16_UNORM) + { + srvDesc.Format = DXGI_FORMAT_R16_UNORM; + } + else if (createInfo.Format == TextureFormat::D24_UNORM_S8_UINT) + { + srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + } + else if (createInfo.Format == TextureFormat::D32_FLOAT_S8_UINT) + { + srvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; + } + + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MostDetailedMip = 0; + srvDesc.Texture2D.MipLevels = numMips; + srvDesc.Texture2D.PlaneSlice = 0; + srvDesc.Texture2D.ResourceMinLODClamp = 0.0f; + + d3d12Driver->D3D12Device->CreateShaderResourceView(resource, &srvDesc, descriptor.CpuHandle); + } + } + + return reinterpret_cast(textureContainer); + } + + void D3D12_DestroyTexture(NonNullPtr driver, NonNullPtr texture) + { + auto* d3d12Driver = static_cast(driver.Get()); + auto* textureContainer = reinterpret_cast(texture.Get()); + + for (uint32 i = 0; i < textureContainer->Count; ++i) + { + D3D12Texture* d3d12Texture = textureContainer->Textures[i]; + for (uint32 j = 0; j < d3d12Texture->SubresourceCount; ++j) + { + D3D12TextureSubresource& sub = d3d12Texture->Subresources[j]; + if (sub.RTVHandles) + { + ReleaseStagingDescriptor(d3d12Driver, sub.RTVHandles[0]); + Free(sub.RTVHandles); + } + if (sub.DSVHandle.Heap) + { + ReleaseStagingDescriptor(d3d12Driver, sub.DSVHandle); + } + } + d3d12Texture->Resource->Release(); + Free(d3d12Texture->Subresources); + Free(d3d12Texture); + } + + Free(textureContainer->Textures); + Free(textureContainer); + } + // End Texture + + // Begin Command list + index_t GetNewCommandListID() + { + return CommandListID++; + } + + bool HasD3D12CommandListForQueueType(NonNullPtr commandList, QueueType queueType) + { + switch (queueType) + { + case QueueType::Graphics: return commandList->GraphicsCommandList.CommandList != nullptr; + case QueueType::Compute: return commandList->ComputeCommandList.CommandList != nullptr; + case QueueType::Copy: return commandList->CopyCommandList.CommandList != nullptr; + default: return false; + } + } + + void DestroyCommandList(NonNullPtr commandList) + { + // TODO : Handle other kind of command list (copy compute) + if (commandList->GraphicsCommandList.CommandList) + { + commandList->GraphicsCommandList.CommandList->Release(); + } + + commandList->GraphicsCommandList.Allocator->Release(); + } + + bool CreateAllocator(NonNullPtr driver, NonNullPtr baseData, D3D12_COMMAND_QUEUE_DESC queueDesc) + { + HRESULT result = driver->D3D12Device->CreateCommandAllocator(queueDesc.Type, IID_ID3D12CommandAllocator, + reinterpret_cast(&baseData->Allocator)); + if (FAILED(result)) + { + AssertHR(result, "Cannot create ID3D12CommandAllocator"); + return false; + } + + baseData->Allocator->Reset(); + return true; + } + + bool CreateD3D12CommandListForQueueType(NonNullPtr driver, NonNullPtr commandList, QueueType queueType) + { + // TODO: String library + std::wstring wide_str = L"CommandList ID:" + std::to_wstring(commandList->ID); + + // TODO: Factorize this. Flemme + + // Get Proper allocator for the frame. Reset all allocators and the command list with current frame allocator + auto& queueDesc = driver->QueueDesc[ToUnderlying(queueType)]; + switch (queueType) + { + case QueueType::Graphics: + { + CreateAllocator(driver, &commandList->GraphicsCommandList, queueDesc); + ID3D12GraphicsCommandList6* d3d12GraphicsCommandList = nullptr; + HRESULT result = + driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type, + D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList6, + reinterpret_cast(&d3d12GraphicsCommandList)); + if (FAILED(result)) + { + Assert(false, "Error not implemented: cannot create ID3D12GraphicsCommandList6 (graphics or " + "compute command list"); + return false; + } + + commandList->GraphicsCommandList.CommandList = d3d12GraphicsCommandList; + d3d12GraphicsCommandList->SetName(wide_str.c_str()); + d3d12GraphicsCommandList->Reset(commandList->GraphicsCommandList.Allocator, nullptr); + + return true; + } + case QueueType::Compute: + { + CreateAllocator(driver, &commandList->ComputeCommandList, queueDesc); + ID3D12GraphicsCommandList6* d3d12GraphicsCommandList = nullptr; + HRESULT result = + driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type, + D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList6, + reinterpret_cast(&d3d12GraphicsCommandList)); + if (FAILED(result)) + { + Assert(false, "Error not implemented: cannot create ID3D12GraphicsCommandList6 (graphics or " + "compute command list"); + return false; + } + + commandList->ComputeCommandList.CommandList = d3d12GraphicsCommandList; + d3d12GraphicsCommandList->SetName(wide_str.c_str()); + d3d12GraphicsCommandList->Reset(commandList->ComputeCommandList.Allocator, nullptr); + + return true; + } + case QueueType::Copy: + { + CreateAllocator(driver, &commandList->CopyCommandList, queueDesc); + ID3D12GraphicsCommandList* d3d12CopyCommandList = nullptr; + HRESULT result = driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type, + D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList, + reinterpret_cast(&d3d12CopyCommandList)); + + if (FAILED(result)) + { + AssertHR(result, "cannot create ID3D12GraphicsCommandList (copy command list)"); + return false; + } + commandList->CopyCommandList.CommandList = d3d12CopyCommandList; + d3d12CopyCommandList->SetName(wide_str.c_str()); + d3d12CopyCommandList->Reset(commandList->CopyCommandList.Allocator, nullptr); + + return true; + } + default: return false; + } + } + + bool AllocateCommandList(NonNullPtr driver, QueueType queueType) + { + if (driver->AvailableCommandLists == nullptr) + { + driver->AvailableCommandLists = + ArenaPushArray(driver->DriverArena, + kMaxCommandListCount JULIET_DEBUG_PARAM("Command list count {}", kMaxCommandListCount)); + driver->AvailableCommandListCapacity = kMaxCommandListCount; + } + const index_t id = GetNewCommandListID(); + + auto* commandList = + ArenaPushStruct(driver->DriverArena JULIET_DEBUG_PARAM("D3D12CommandList [{}]", id)); + if (!commandList) + { + Log(LogLevel::Error, LogCategory::Graphics, "Cannot allocate D3D12CommandList: Out of memory"); + DestroyCommandList(commandList); + return false; + } + + driver->AvailableCommandLists[driver->AvailableCommandListCount] = commandList; + driver->AvailableCommandListCount += 1; + + commandList->ID = id; + commandList->Driver = driver; + + // Window Handling + commandList->PresentDataCapacity = kMaxPresentDataPerCommandList; + commandList->PresentDataCount = 0; + commandList->PresentDatas = ArenaPushArray( + driver->DriverArena, + kMaxPresentDataPerCommandList JULIET_DEBUG_PARAM("Command list [{}] D3D12PresentData ptr array count " + "{}", + id, kMaxPresentDataPerCommandList)); + + // Resource tracking + commandList->UsedTextureCapacity = kMaxTexturePerCommandList; + commandList->UsedTextureCount = 0; + commandList->UsedTextures = + ArenaPushArray(driver->DriverArena, + kMaxTexturePerCommandList JULIET_DEBUG_PARAM("Command list [{}] D3D12Texture " + "ptr array count " + "{}", + id, kMaxTexturePerCommandList)); + + commandList->UsedGraphicsPipelineCapacity = kMaxGraphicsPipelinePerCommandList; + commandList->UsedGraphicsPipelineCount = 0; + commandList->UsedGraphicsPipelines = ArenaPushArray( + driver->DriverArena, + kMaxTexturePerCommandList JULIET_DEBUG_PARAM("Command list [{}] D3D12GraphicsPipeline ptr array count " + "{}", + id, kMaxTexturePerCommandList)); + + // TODO : Simplify this + if (!HasD3D12CommandListForQueueType(commandList, queueType)) + { + if (!CreateD3D12CommandListForQueueType(driver, commandList, queueType)) + { + Log(LogLevel::Error, LogCategory::Graphics, "Cannot Create D3D12 command list"); + DestroyCommandList(commandList); + return false; + } + } + + return true; + } + + D3D12CommandList* AcquireCommandListFromPool(NonNullPtr driver, QueueType queueType) + { + if (driver->AvailableCommandListCount == 0) + { + if (!AllocateCommandList(driver, queueType)) + { + return nullptr; + } + } + + D3D12CommandList* commandList = driver->AvailableCommandLists[driver->AvailableCommandListCount - 1]; + driver->AvailableCommandListCount -= 1; + + return commandList; + } + + CommandList* D3D12_AcquireCommandList(NonNullPtr driver, QueueType queueType) + { + auto* d3d12Driver = static_cast(driver.Get()); + + D3D12CommandList* commandList = AcquireCommandListFromPool(d3d12Driver, queueType); + + commandList->AutoReleaseFence = true; + + return reinterpret_cast(commandList); + } + + void D3D12_SetViewPort(NonNullPtr commandList, const GraphicsViewPort& viewPort) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + + D3D12_VIEWPORT d3d12Viewport; + d3d12Viewport.TopLeftX = viewPort.X; + d3d12Viewport.TopLeftY = viewPort.Y; + d3d12Viewport.Width = viewPort.Width; + d3d12Viewport.Height = viewPort.Height; + d3d12Viewport.MinDepth = viewPort.MinDepth; + d3d12Viewport.MaxDepth = viewPort.MaxDepth; + d3d12CommandList->GraphicsCommandList.CommandList->RSSetViewports(1, &d3d12Viewport); + } + + void D3D12_SetScissorRect(NonNullPtr commandList, const struct Rectangle& rectangle) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + D3D12_RECT scissorRect; + scissorRect.left = rectangle.X; + scissorRect.top = rectangle.Y; + scissorRect.right = rectangle.X + rectangle.Width; + scissorRect.bottom = rectangle.Y + rectangle.Height; + d3d12CommandList->GraphicsCommandList.CommandList->RSSetScissorRects(1, &scissorRect); + } + + void D3D12_SetBlendConstants(NonNullPtr commandList, FColor blendConstants) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + FLOAT blendFactor[4] = { blendConstants.R, blendConstants.G, blendConstants.B, blendConstants.A }; + d3d12CommandList->GraphicsCommandList.CommandList->OMSetBlendFactor(blendFactor); + } + + void D3D12_SetStencilReference(NonNullPtr commandList, uint8 reference) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + d3d12CommandList->GraphicsCommandList.CommandList->OMSetStencilRef(reference); + } + + void D3D12_SetIndexBuffer(NonNullPtr commandList, NonNullPtr buffer, + IndexFormat format, size_t indexCount, index_t offset) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + auto* d3d12Buffer = reinterpret_cast(buffer.Get()); + + // Transition to INDEX_BUFFER state if needed + if (d3d12Buffer->CurrentState != D3D12_RESOURCE_STATE_GENERIC_READ) + { + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrier.Transition.pResource = d3d12Buffer->Handle; + barrier.Transition.StateBefore = d3d12Buffer->CurrentState; + barrier.Transition.StateAfter = + D3D12_RESOURCE_STATE_GENERIC_READ; // Since we use a mega buffer we use the generic read that includes D3D12_RESOURCE_STATE_INDEX_BUFFER + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + + d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier); + d3d12Buffer->CurrentState = D3D12_RESOURCE_STATE_GENERIC_READ; + } + + D3D12_INDEX_BUFFER_VIEW ibView; + ibView.BufferLocation = d3d12Buffer->Handle->GetGPUVirtualAddress() + offset; + if (format == IndexFormat::UInt16) + { + ibView.SizeInBytes = static_cast(indexCount * sizeof(uint16)); + ibView.Format = DXGI_FORMAT_R16_UINT; + } + else + { + ibView.SizeInBytes = static_cast(indexCount * sizeof(uint32)); + ibView.Format = DXGI_FORMAT_R32_UINT; + } + + d3d12CommandList->GraphicsCommandList.CommandList->IASetIndexBuffer(&ibView); + } + + void D3D12_SetPushConstants(NonNullPtr commandList, ShaderStage /*stage*/, uint32 rootParameterIndex, + uint32 numConstants, const void* constants) + { + auto d3d12CommandList = reinterpret_cast(commandList.Get()); + // For now we assume Graphics Root Signature. Compute support would need a check or separate function. + d3d12CommandList->GraphicsCommandList.CommandList->SetGraphicsRoot32BitConstants(rootParameterIndex, + numConstants, constants, 0); + } + + void SetDescriptorHeaps(NonNullPtr commandList) + { + ID3D12DescriptorHeap* heaps[2]; + D3D12DescriptorHeap* viewHeap = nullptr; + D3D12DescriptorHeap* samplerHeap = nullptr; + + viewHeap = commandList->Driver->BindlessDescriptorHeap; + + samplerHeap = AcquireSamplerHeapFromPool(commandList->Driver); + + commandList->CRB_SRV_UAV_Heap = viewHeap; + commandList->Sampler_Heap = samplerHeap; + + heaps[0] = viewHeap->Handle; + heaps[1] = samplerHeap->Handle; + + commandList->GraphicsCommandList.CommandList->SetDescriptorHeaps(2, heaps); + } + #define TRACK_RESOURCE(resource, type, array, count, capacity) \ uint32 i; \ \ @@ -3674,1025 +3651,1014 @@ namespace Juliet commandList->count += 1; \ ++(resource)->ReferenceCount; - void TrackGraphicsPipeline(NonNullPtr commandList, NonNullPtr pipeline) + void TrackGraphicsPipeline(NonNullPtr commandList, NonNullPtr pipeline) + { + TRACK_RESOURCE(pipeline, D3D12GraphicsPipeline*, UsedGraphicsPipelines, UsedGraphicsPipelineCount, UsedGraphicsPipelineCapacity) + } + + void TrackTexture(NonNullPtr commandList, NonNullPtr texture) + { + TRACK_RESOURCE(texture, D3D12Texture*, UsedTextures, UsedTextureCount, UsedTextureCapacity) + } + + bool D3D12_SubmitCommandLists(NonNullPtr commandList) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + auto* d3d12Driver = d3d12CommandList->Driver; + // TODO : Use QueueType to choose the correct CommandList and Command Queue + // Only use graphics for now + + // Transition present textures to present mode + for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1) { - TRACK_RESOURCE(pipeline, D3D12GraphicsPipeline*, UsedGraphicsPipelines, UsedGraphicsPipelineCount, UsedGraphicsPipelineCapacity) + uint32 swapchainIndex = d3d12CommandList->PresentDatas[i].SwapChainImageIndex; + D3D12TextureContainer* container = + &d3d12CommandList->PresentDatas[i].WindowData->SwapChainTextureContainers[swapchainIndex]; + D3D12TextureSubresource* subresource = FetchTextureSubresource(container, 0, 0); + + D3D12_RESOURCE_BARRIER barrierDesc; + barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrierDesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; + barrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; + barrierDesc.Transition.pResource = subresource->Parent->Resource; + barrierDesc.Transition.Subresource = subresource->Index; + + d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrierDesc); } - void TrackTexture(NonNullPtr commandList, NonNullPtr texture) + // Notify the command buffer that we have completed recording + HRESULT result = d3d12CommandList->GraphicsCommandList.CommandList->Close(); + if (FAILED(result)) { - TRACK_RESOURCE(texture, D3D12Texture*, UsedTextures, UsedTextureCount, UsedTextureCapacity) + D3D12_LogError(d3d12Driver->D3D12Device, "Failed to close command list!", result); + return false; } - bool D3D12_SubmitCommandLists(NonNullPtr commandList) - { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - auto* d3d12Driver = d3d12CommandList->Driver; - // TODO : Use QueueType to choose the correct CommandList and Command Queue - // Only use graphics for now + ID3D12CommandList* ppCommandLists[] = { d3d12CommandList->GraphicsCommandList.CommandList }; - // Transition present textures to present mode - for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1) + // Submit the command list to the queue + d3d12Driver->GraphicsQueue->ExecuteCommandLists(1, ppCommandLists); + + // Acquire a fence and set it to the in-flight fence + d3d12CommandList->InFlightFence = + D3D12_AcquireFence(d3d12Driver JULIET_DEBUG_PARAM(ConstString("SubmitCommandLists"))); + if (!d3d12CommandList->InFlightFence) + { + return false; + } + + // Mark that a fence should be signaled after command list execution + result = d3d12Driver->GraphicsQueue->Signal(d3d12CommandList->InFlightFence->Handle, D3D12_FENCE_SIGNAL_VALUE); + if (FAILED(result)) + { + D3D12_LogError(d3d12Driver->D3D12Device, "Failed to enqueue fence signal!", result); + return false; + } + + // Mark the command list as submitted + [[maybe_unused]] const uint32 newValue = static_cast(d3d12Driver->SubmittedCommandListCount) + 1U; + Assert(newValue <= 0xFF && "Command List count exceeded uint8 capacity!"); + Assert(newValue <= d3d12Driver->SubmittedCommandListCapacity); + + d3d12Driver->SubmittedCommandLists[d3d12Driver->SubmittedCommandListCount] = d3d12CommandList; + d3d12Driver->SubmittedCommandListCount += 1; + + bool success = true; + for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1) + { + D3D12PresentData* presentData = &d3d12CommandList->PresentDatas[i]; + auto* windowData = presentData->WindowData; + + // NOTE: flip discard always supported since DXGI 1.4 is required + uint32 syncInterval = 1; + if (windowData->PresentMode == PresentMode::Immediate || windowData->PresentMode == PresentMode::Mailbox) { - uint32 swapchainIndex = d3d12CommandList->PresentDatas[i].SwapChainImageIndex; - D3D12TextureContainer* container = - &d3d12CommandList->PresentDatas[i].WindowData->SwapChainTextureContainers[swapchainIndex]; - D3D12TextureSubresource* subresource = FetchTextureSubresource(container, 0, 0); - - D3D12_RESOURCE_BARRIER barrierDesc; - barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrierDesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; - barrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; - barrierDesc.Transition.pResource = subresource->Parent->Resource; - barrierDesc.Transition.Subresource = subresource->Index; - - d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrierDesc); + syncInterval = 0; } - // Notify the command buffer that we have completed recording - HRESULT result = d3d12CommandList->GraphicsCommandList.CommandList->Close(); + uint32 presentFlags = 0; + if (d3d12Driver->IsTearingSupported && windowData->PresentMode == PresentMode::Immediate) + { + presentFlags = DXGI_PRESENT_ALLOW_TEARING; + } + + result = windowData->SwapChain->Present(syncInterval, presentFlags); if (FAILED(result)) { - D3D12_LogError(d3d12Driver->D3D12Device, "Failed to close command list!", result); - return false; + success = false; } - ID3D12CommandList* ppCommandLists[] = { d3d12CommandList->GraphicsCommandList.CommandList }; + windowData->SwapChainTextureContainers[presentData->SwapChainImageIndex].ActiveTexture->Resource->Release(); - // Submit the command list to the queue - d3d12Driver->GraphicsQueue->ExecuteCommandLists(1, ppCommandLists); - - // Acquire a fence and set it to the in-flight fence - d3d12CommandList->InFlightFence = - D3D12_AcquireFence(d3d12Driver JULIET_DEBUG_PARAM(ConstString("SubmitCommandLists"))); - if (!d3d12CommandList->InFlightFence) - { - return false; - } - - // Mark that a fence should be signaled after command list execution - result = d3d12Driver->GraphicsQueue->Signal(d3d12CommandList->InFlightFence->Handle, D3D12_FENCE_SIGNAL_VALUE); - if (FAILED(result)) - { - D3D12_LogError(d3d12Driver->D3D12Device, "Failed to enqueue fence signal!", result); - return false; - } - - // Mark the command list as submitted - [[maybe_unused]] const uint32 newValue = static_cast(d3d12Driver->SubmittedCommandListCount) + 1U; - Assert(newValue <= 0xFF && "Command List count exceeded uint8 capacity!"); - Assert(newValue <= d3d12Driver->SubmittedCommandListCapacity); - - d3d12Driver->SubmittedCommandLists[d3d12Driver->SubmittedCommandListCount] = d3d12CommandList; - d3d12Driver->SubmittedCommandListCount += 1; - - bool success = true; - for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1) - { - D3D12PresentData* presentData = &d3d12CommandList->PresentDatas[i]; - auto* windowData = presentData->WindowData; - - // NOTE: flip discard always supported since DXGI 1.4 is required - uint32 syncInterval = 1; - if (windowData->PresentMode == PresentMode::Immediate || windowData->PresentMode == PresentMode::Mailbox) - { - syncInterval = 0; - } - - uint32 presentFlags = 0; - if (d3d12Driver->IsTearingSupported && windowData->PresentMode == PresentMode::Immediate) - { - presentFlags = DXGI_PRESENT_ALLOW_TEARING; - } - - result = windowData->SwapChain->Present(syncInterval, presentFlags); - if (FAILED(result)) - { - success = false; - } - - windowData->SwapChainTextureContainers[presentData->SwapChainImageIndex].ActiveTexture->Resource->Release(); - - windowData->InFlightFences[windowData->WindowFrameCounter] = - reinterpret_cast(d3d12CommandList->InFlightFence); - d3d12CommandList->InFlightFence->ReferenceCount += 1; - windowData->WindowFrameCounter = (windowData->WindowFrameCounter + 1) % d3d12Driver->FramesInFlight; - } - - // Check for cleanups - { - int32 i = 0; - while (i < d3d12Driver->SubmittedCommandListCount) - { - uint64 fenceValue = d3d12Driver->SubmittedCommandLists[i]->InFlightFence->Handle->GetCompletedValue(); - if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) - { - success &= D3D12_CleanCommandList(d3d12Driver, d3d12Driver->SubmittedCommandLists[i], false); - // CleanCommandList swaps [i] with last and decrements count. - // Don't increment — re-check the swapped-in element. - } - else - { - i += 1; - } - } - } - - DisposePendingResourcces(d3d12Driver); - - ++d3d12Driver->FrameCounter; - - return success; - } - // End Command List - - // Begin Render Pass - void D3D12_BeginRenderPass(NonNullPtr commandList, NonNullPtr colorTargetInfos, - uint32 colorTargetInfoCount, const DepthStencilTargetInfo* depthStencilTargetInfo) - { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - - uint32 frameBufferWidth = uint32Max; - uint32 frameBufferHeight = uint32Max; - - for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx) - { - auto* container = reinterpret_cast(colorTargetInfos[idx].TargetTexture); - uint32 width = container->Header.CreateInfo.Width >> colorTargetInfos[idx].MipLevel; - uint32 height = container->Header.CreateInfo.Height >> colorTargetInfos[idx].MipLevel; - - // Scale the framebuffer to fit the smallest target. - frameBufferWidth = Min(width, frameBufferWidth); - frameBufferHeight = Min(height, frameBufferHeight); - } - - // Depth Stencil and DSV - D3D12_CPU_DESCRIPTOR_HANDLE DSV; - bool hasDSV = false; - if (depthStencilTargetInfo && depthStencilTargetInfo->TargetTexture) - { - auto* container = reinterpret_cast(depthStencilTargetInfo->TargetTexture); - uint32 width = container->Header.CreateInfo.Width; - uint32 height = container->Header.CreateInfo.Height; - - frameBufferWidth = Min(width, frameBufferWidth); - frameBufferHeight = Min(height, frameBufferHeight); - - D3D12TextureSubresource* subresource = - PrepareTextureSubresourceForWrite(d3d12CommandList, container, 0, 0, false, D3D12_RESOURCE_STATE_DEPTH_WRITE); - - DSV = subresource->DSVHandle.CpuHandle; - hasDSV = true; - d3d12CommandList->DepthStencilSubresource = subresource; - - TrackTexture(d3d12CommandList, subresource->Parent); - - if (depthStencilTargetInfo->LoadOperation == LoadOperation::Clear) - { - D3D12_CLEAR_FLAGS clearFlags = D3D12_CLEAR_FLAG_DEPTH; - // TODO: Check if texture has stencil - // if (HasStencil(container->Header.CreateInfo.Format)) clearFlags |= D3D12_CLEAR_FLAG_STENCIL; - - d3d12CommandList->GraphicsCommandList.CommandList->ClearDepthStencilView(DSV, clearFlags, - depthStencilTargetInfo->ClearDepth, - depthStencilTargetInfo->ClearStencil, - 0, nullptr); - } - } - - D3D12_CPU_DESCRIPTOR_HANDLE RTVs[GPUDriver::kMaxColorTargetInfo]; - for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx) - { - auto* container = reinterpret_cast(colorTargetInfos[idx].TargetTexture); - D3D12TextureSubresource* subresource = PrepareTextureSubresourceForWrite( - d3d12CommandList, container, - container->Header.CreateInfo.Type == TextureType::Texture_3D ? 0 : colorTargetInfos[idx].LayerIndex, - colorTargetInfos[idx].MipLevel, colorTargetInfos[idx].CycleTexture, D3D12_RESOURCE_STATE_RENDER_TARGET); - - uint32 RTVIndex = - container->Header.CreateInfo.Type == TextureType::Texture_3D ? colorTargetInfos[idx].DepthPlane : 0; - D3D12_CPU_DESCRIPTOR_HANDLE rtv = subresource->RTVHandles[RTVIndex].CpuHandle; - - if (colorTargetInfos[idx].LoadOperation == LoadOperation::Clear) - { - float clearColor[4]; - clearColor[0] = colorTargetInfos[idx].ClearColor.R; - clearColor[1] = colorTargetInfos[idx].ClearColor.G; - clearColor[2] = colorTargetInfos[idx].ClearColor.B; - clearColor[3] = colorTargetInfos[idx].ClearColor.A; - - d3d12CommandList->GraphicsCommandList.CommandList->ClearRenderTargetView(rtv, clearColor, 0, nullptr); - } - - RTVs[idx] = rtv; - d3d12CommandList->ColorTargetSubresources[idx] = subresource; - - TrackTexture(d3d12CommandList, subresource->Parent); - - if (colorTargetInfos[idx].StoreOperation == StoreOperation::Resolve || - colorTargetInfos[idx].StoreOperation == StoreOperation::ResolveAndStore) - { - auto resolveContainer = reinterpret_cast(colorTargetInfos[idx].ResolveTexture); - D3D12TextureSubresource* resolveSubresource = - PrepareTextureSubresourceForWrite(d3d12CommandList, resolveContainer, colorTargetInfos[idx].ResolveLayerIndex, - colorTargetInfos[idx].ResolveMipLevel, colorTargetInfos[idx].CycleResolveTexture, - D3D12_RESOURCE_STATE_RESOLVE_DEST); - - d3d12CommandList->ColorResolveSubresources[idx] = resolveSubresource; - - TrackTexture(d3d12CommandList, resolveSubresource->Parent); - } - } - - d3d12CommandList->GraphicsCommandList.CommandList->OMSetRenderTargets(colorTargetInfoCount, RTVs, false, - hasDSV ? &DSV : nullptr); - - // Set defaults graphics states - GraphicsViewPort defaultViewport; - defaultViewport.X = 0.f; - defaultViewport.Y = 0.f; - defaultViewport.Width = static_cast(frameBufferWidth); - defaultViewport.Height = static_cast(frameBufferHeight); - defaultViewport.MinDepth = 0.f; - defaultViewport.MaxDepth = 1.f; - D3D12_SetViewPort(commandList, defaultViewport); - - Rectangle defaultScissor; - defaultScissor.X = 0; - defaultScissor.Y = 0; - defaultScissor.Width = static_cast(frameBufferWidth); - defaultScissor.Height = static_cast(frameBufferHeight); - D3D12_SetScissorRect(commandList, defaultScissor); - - D3D12_SetStencilReference(commandList, 0); - - FColor blendConstants; - blendConstants.R = 1.0f; - blendConstants.G = 1.0f; - blendConstants.B = 1.0f; - blendConstants.A = 1.0f; - D3D12_SetBlendConstants(commandList, blendConstants); + windowData->InFlightFences[windowData->WindowFrameCounter] = reinterpret_cast(d3d12CommandList->InFlightFence); + d3d12CommandList->InFlightFence->ReferenceCount += 1; + windowData->WindowFrameCounter = (windowData->WindowFrameCounter + 1) % d3d12Driver->FramesInFlight; } - void D3D12_EndRenderPass(NonNullPtr commandList) + // Check for cleanups { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - - // Reset Color Target state and optionally resolve color texture - for (uint32 idx = 0; idx < GPUDriver::kMaxColorTargetInfo; ++idx) + int32 i = 0; + while (i < d3d12Driver->SubmittedCommandListCount) { - if (d3d12CommandList->ColorTargetSubresources[idx]) + uint64 fenceValue = d3d12Driver->SubmittedCommandLists[i]->InFlightFence->Handle->GetCompletedValue(); + if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) { - if (d3d12CommandList->ColorResolveSubresources[idx]) - { - TextureSubresourceBarrier(d3d12CommandList, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, - d3d12CommandList->ColorTargetSubresources[idx]); - d3d12CommandList->GraphicsCommandList.CommandList->ResolveSubresource( - d3d12CommandList->ColorResolveSubresources[idx]->Parent->Resource, - d3d12CommandList->ColorResolveSubresources[idx]->Index, - d3d12CommandList->ColorTargetSubresources[idx]->Parent->Resource, - d3d12CommandList->ColorTargetSubresources[idx]->Index, - ConvertToD3D12TextureFormat( - d3d12CommandList->ColorTargetSubresources[idx]->Parent->Container->Header.CreateInfo.Format)); - - TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, - d3d12CommandList->ColorTargetSubresources[idx], - D3D12_RESOURCE_STATE_RESOLVE_SOURCE); - - TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, - d3d12CommandList->ColorResolveSubresources[idx], - D3D12_RESOURCE_STATE_RESOLVE_DEST); - } - else - { - TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, - d3d12CommandList->ColorTargetSubresources[idx], - D3D12_RESOURCE_STATE_RENDER_TARGET); - } + success &= D3D12_CleanCommandList(d3d12Driver, d3d12Driver->SubmittedCommandLists[i], false); + // CleanCommandList swaps [i] with last and decrements count. + // Don't increment — re-check the swapped-in element. + } + else + { + i += 1; } } - - // Reset Depth Stencil state - if (d3d12CommandList->DepthStencilSubresource) - { - TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->DepthStencilSubresource, - D3D12_RESOURCE_STATE_DEPTH_WRITE); - d3d12CommandList->DepthStencilSubresource = nullptr; - } - d3d12CommandList->CurrentGraphicsPipeline = nullptr; - - d3d12CommandList->GraphicsCommandList.CommandList->OMSetRenderTargets(0, nullptr, false, nullptr); - - // Reset bind states - ZeroArray(d3d12CommandList->ColorTargetSubresources); - ZeroArray(d3d12CommandList->ColorResolveSubresources); - // TODO : reset depth stencil subresources - // d3d12CommandList->DepthStencilTextureSubresource = NULL; - - // TODO : vertex buffer - // TODO :Vertex sampler and fragment sampler - - // ZeroArray(d3d12CommandList->VertexBuffers); - // ZeroArray(d3d12CommandList->VertexBufferOffsets); - // d3d12CommandList->VertexBufferCount = 0; - // - // ZeroArray(d3d12CommandList->VertexSamplerTextures); - // ZeroArray(d3d12CommandList->VertexSamplers); - // ZeroArray(d3d12CommandList->VertexStorageTextures); - // ZeroArray(d3d12CommandList->VertexStorageBuffers); - // - // ZeroArray(d3d12CommandList->FragmentSamplerTextures); - // ZeroArray(d3d12CommandList->FragmentSamplers); - // ZeroArray(d3d12CommandList->FragmentStorageTextures); - // ZeroArray(d3d12CommandList->FragmentStorageBuffers); } - void D3D12_BindGraphicsPipeline(NonNullPtr commandList, NonNullPtr graphicsPipeline) + DisposePendingResourcces(d3d12Driver); + + ++d3d12Driver->FrameCounter; + + return success; + } + // End Command List + + // Begin Render Pass + void D3D12_BeginRenderPass(NonNullPtr commandList, NonNullPtr colorTargetInfos, + uint32 colorTargetInfoCount, const DepthStencilTargetInfo* depthStencilTargetInfo) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + + uint32 frameBufferWidth = uint32Max; + uint32 frameBufferHeight = uint32Max; + + for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx) { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - auto pipeline = reinterpret_cast(graphicsPipeline.Get()); + auto* container = reinterpret_cast(colorTargetInfos[idx].TargetTexture); + uint32 width = container->Header.CreateInfo.Width >> colorTargetInfos[idx].MipLevel; + uint32 height = container->Header.CreateInfo.Height >> colorTargetInfos[idx].MipLevel; - d3d12CommandList->CurrentGraphicsPipeline = pipeline; - - // Set the Descriptor heap - if (d3d12CommandList->CRB_SRV_UAV_Heap == nullptr) - { - SetDescriptorHeaps(d3d12CommandList); - } - - // Set the pipeline state - d3d12CommandList->GraphicsCommandList.CommandList->SetPipelineState(pipeline->PipelineState); - d3d12CommandList->GraphicsCommandList.CommandList->SetGraphicsRootSignature(pipeline->RootSignature->Handle); - d3d12CommandList->GraphicsCommandList.CommandList->IASetPrimitiveTopology( - JulietToD3D12_PrimitiveType[ToUnderlying(pipeline->PrimitiveType)]); - - // Mark that bindings are needed - d3d12CommandList->NeedVertexSamplerBind = true; - d3d12CommandList->NeedVertexStorageTextureBind = true; - d3d12CommandList->NeedVertexStorageBufferBind = true; - d3d12CommandList->NeedFragmentSamplerBind = true; - d3d12CommandList->NeedFragmentStorageTextureBind = true; - d3d12CommandList->NeedFragmentStorageBufferBind = true; - - for (uint32 idx = 0; idx < GPUDriver::kMaxUniformBuffersPerStage; ++idx) - { - d3d12CommandList->NeedVertexUniformBufferBind[idx] = true; - d3d12CommandList->NeedFragmentUniformBufferBind[idx] = true; - } - - for (uint32 idx = 0; idx < pipeline->VertexUniformBufferCount; ++idx) - { - // if (d3d12CommandList->VertexUniformBuffers[i] == NULL) - // { - // d3d12CommandList->VertexUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(d3d12CommandBuffer); - // } - } - - for (uint32 idx = 0; idx < pipeline->FragmentUniformBufferCount; ++idx) - { - // if (d3d12CommandList->FragmentUniformBuffers[i] == NULL) - // { - // d3d12CommandList->FragmentUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(d3d12CommandBuffer); - // } - } - - TrackGraphicsPipeline(d3d12CommandList, pipeline); + // Scale the framebuffer to fit the smallest target. + frameBufferWidth = Min(width, frameBufferWidth); + frameBufferHeight = Min(height, frameBufferHeight); } - void D3D12_DrawPrimitives(NonNullPtr commandList, uint32 numVertices, uint32 numInstances, - uint32 firstVertex, uint32 firstInstance) + // Depth Stencil and DSV + D3D12_CPU_DESCRIPTOR_HANDLE DSV; + bool hasDSV = false; + if (depthStencilTargetInfo && depthStencilTargetInfo->TargetTexture) { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - // TODO : Last missing piece - // D3D12_INTERNAL_BindGraphicsResources(d3d12CommandBuffer); + auto* container = reinterpret_cast(depthStencilTargetInfo->TargetTexture); + uint32 width = container->Header.CreateInfo.Width; + uint32 height = container->Header.CreateInfo.Height; - d3d12CommandList->GraphicsCommandList.CommandList->DrawInstanced(numVertices, numInstances, firstVertex, firstInstance); + frameBufferWidth = Min(width, frameBufferWidth); + frameBufferHeight = Min(height, frameBufferHeight); + + D3D12TextureSubresource* subresource = + PrepareTextureSubresourceForWrite(d3d12CommandList, container, 0, 0, false, D3D12_RESOURCE_STATE_DEPTH_WRITE); + + DSV = subresource->DSVHandle.CpuHandle; + hasDSV = true; + d3d12CommandList->DepthStencilSubresource = subresource; + + TrackTexture(d3d12CommandList, subresource->Parent); + + if (depthStencilTargetInfo->LoadOperation == LoadOperation::Clear) + { + D3D12_CLEAR_FLAGS clearFlags = D3D12_CLEAR_FLAG_DEPTH; + // TODO: Check if texture has stencil + // if (HasStencil(container->Header.CreateInfo.Format)) clearFlags |= D3D12_CLEAR_FLAG_STENCIL; + + d3d12CommandList->GraphicsCommandList.CommandList->ClearDepthStencilView(DSV, clearFlags, + depthStencilTargetInfo->ClearDepth, + depthStencilTargetInfo->ClearStencil, + 0, nullptr); + } } - void D3D12_DrawIndexedPrimitives(NonNullPtr commandList, uint32 numIndices, uint32 numInstances, - uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance) + D3D12_CPU_DESCRIPTOR_HANDLE RTVs[GPUDriver::kMaxColorTargetInfo]; + for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx) { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - d3d12CommandList->GraphicsCommandList.CommandList->DrawIndexedInstanced(numIndices, numInstances, firstIndex, - static_cast(vertexOffset), firstInstance); - } - // End Render Pass + auto* container = reinterpret_cast(colorTargetInfos[idx].TargetTexture); + D3D12TextureSubresource* subresource = PrepareTextureSubresourceForWrite( + d3d12CommandList, container, + container->Header.CreateInfo.Type == TextureType::Texture_3D ? 0 : colorTargetInfos[idx].LayerIndex, + colorTargetInfos[idx].MipLevel, colorTargetInfos[idx].CycleTexture, D3D12_RESOURCE_STATE_RENDER_TARGET); - bool D3D12_AttachToWindow(NonNullPtr driver, NonNullPtr window) - { - auto* d3d12Driver = static_cast(driver.Get()); + uint32 RTVIndex = container->Header.CreateInfo.Type == TextureType::Texture_3D ? colorTargetInfos[idx].DepthPlane : 0; + D3D12_CPU_DESCRIPTOR_HANDLE rtv = subresource->RTVHandles[RTVIndex].CpuHandle; - // TODO : Support more than one window - if (d3d12Driver->WindowData) + if (colorTargetInfos[idx].LoadOperation == LoadOperation::Clear) { - Assert(false, "D3D12 renderer already attached to the window. Right now we handle only one Window."); - return false; + float clearColor[4]; + clearColor[0] = colorTargetInfos[idx].ClearColor.R; + clearColor[1] = colorTargetInfos[idx].ClearColor.G; + clearColor[2] = colorTargetInfos[idx].ClearColor.B; + clearColor[3] = colorTargetInfos[idx].ClearColor.A; + + d3d12CommandList->GraphicsCommandList.CommandList->ClearRenderTargetView(rtv, clearColor, 0, nullptr); } - auto* windowData = static_cast(Calloc(1, sizeof(D3D12WindowData))); - if (!windowData) + RTVs[idx] = rtv; + d3d12CommandList->ColorTargetSubresources[idx] = subresource; + + TrackTexture(d3d12CommandList, subresource->Parent); + + if (colorTargetInfos[idx].StoreOperation == StoreOperation::Resolve || + colorTargetInfos[idx].StoreOperation == StoreOperation::ResolveAndStore) { - Log(LogLevel::Error, LogCategory::Graphics, "OOM: D3D12WindowData"); - return false; + auto resolveContainer = reinterpret_cast(colorTargetInfos[idx].ResolveTexture); + D3D12TextureSubresource* resolveSubresource = + PrepareTextureSubresourceForWrite(d3d12CommandList, resolveContainer, colorTargetInfos[idx].ResolveLayerIndex, + colorTargetInfos[idx].ResolveMipLevel, colorTargetInfos[idx].CycleResolveTexture, + D3D12_RESOURCE_STATE_RESOLVE_DEST); + + d3d12CommandList->ColorResolveSubresources[idx] = resolveSubresource; + + TrackTexture(d3d12CommandList, resolveSubresource->Parent); } - d3d12Driver->WindowData = windowData; - - windowData->Window = window; - - if (!CreateSwapChain(d3d12Driver, windowData, SwapChainComposition::SDR, PresentMode::VSync)) - { - Log(LogLevel::Error, LogCategory::Graphics, "AttachToWindow failure: Cannot create Swap Chain."); - Free(windowData); - return false; - } - - d3d12Driver->WindowData = windowData; - - return true; } - void D3D12_DetachFromWindow(NonNullPtr driver, NonNullPtr /*window*/) + d3d12CommandList->GraphicsCommandList.CommandList->OMSetRenderTargets(colorTargetInfoCount, RTVs, false, + hasDSV ? &DSV : nullptr); + + // Set defaults graphics states + GraphicsViewPort defaultViewport; + defaultViewport.X = 0.f; + defaultViewport.Y = 0.f; + defaultViewport.Width = static_cast(frameBufferWidth); + defaultViewport.Height = static_cast(frameBufferHeight); + defaultViewport.MinDepth = 0.f; + defaultViewport.MaxDepth = 1.f; + D3D12_SetViewPort(commandList, defaultViewport); + + struct Rectangle defaultScissor; + defaultScissor.X = 0; + defaultScissor.Y = 0; + defaultScissor.Width = static_cast(frameBufferWidth); + defaultScissor.Height = static_cast(frameBufferHeight); + D3D12_SetScissorRect(commandList, defaultScissor); + + D3D12_SetStencilReference(commandList, 0); + + FColor blendConstants; + blendConstants.R = 1.0f; + blendConstants.G = 1.0f; + blendConstants.B = 1.0f; + blendConstants.A = 1.0f; + D3D12_SetBlendConstants(commandList, blendConstants); + } + + void D3D12_EndRenderPass(NonNullPtr commandList) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + + // Reset Color Target state and optionally resolve color texture + for (uint32 idx = 0; idx < GPUDriver::kMaxColorTargetInfo; ++idx) { - auto* d3d12Driver = static_cast(driver.Get()); - auto* windowData = d3d12Driver->WindowData; - Assert(windowData && "Trying to destroy a swapchain but no Window Data exists"); - - D3D12_WaitUntilGPUIsIdle(driver); - - for (uint32 idx = 0; idx < GPUDriver::kMaxFramesInFlight; idx += 1) + if (d3d12CommandList->ColorTargetSubresources[idx]) { - if (windowData->InFlightFences[idx] != nullptr) + if (d3d12CommandList->ColorResolveSubresources[idx]) { - D3D12_ReleaseFence(driver, windowData->InFlightFences[idx] JULIET_DEBUG_PARAM( - ConstString("DeatchFromWindow"))); - windowData->InFlightFences[idx] = nullptr; + TextureSubresourceBarrier(d3d12CommandList, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, + d3d12CommandList->ColorTargetSubresources[idx]); + d3d12CommandList->GraphicsCommandList.CommandList->ResolveSubresource( + d3d12CommandList->ColorResolveSubresources[idx]->Parent->Resource, + d3d12CommandList->ColorResolveSubresources[idx]->Index, + d3d12CommandList->ColorTargetSubresources[idx]->Parent->Resource, + d3d12CommandList->ColorTargetSubresources[idx]->Index, + ConvertToD3D12TextureFormat( + d3d12CommandList->ColorTargetSubresources[idx]->Parent->Container->Header.CreateInfo.Format)); + + TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->ColorTargetSubresources[idx], + D3D12_RESOURCE_STATE_RESOLVE_SOURCE); + + TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->ColorResolveSubresources[idx], + D3D12_RESOURCE_STATE_RESOLVE_DEST); + } + else + { + TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->ColorTargetSubresources[idx], + D3D12_RESOURCE_STATE_RENDER_TARGET); } } - - DestroySwapChain(d3d12Driver, d3d12Driver->WindowData); - - SafeFree(d3d12Driver->WindowData); - d3d12Driver->WindowData = nullptr; } - void DestroyDriver_Internal(NonNullPtr driver) + // Reset Depth Stencil state + if (d3d12CommandList->DepthStencilSubresource) { - // Destroy Descriptor pools - for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) + TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->DepthStencilSubresource, + D3D12_RESOURCE_STATE_DEPTH_WRITE); + d3d12CommandList->DepthStencilSubresource = nullptr; + } + d3d12CommandList->CurrentGraphicsPipeline = nullptr; + + d3d12CommandList->GraphicsCommandList.CommandList->OMSetRenderTargets(0, nullptr, false, nullptr); + + // Reset bind states + ZeroArray(d3d12CommandList->ColorTargetSubresources); + ZeroArray(d3d12CommandList->ColorResolveSubresources); + // TODO : reset depth stencil subresources + // d3d12CommandList->DepthStencilTextureSubresource = NULL; + + // TODO : vertex buffer + // TODO :Vertex sampler and fragment sampler + + // ZeroArray(d3d12CommandList->VertexBuffers); + // ZeroArray(d3d12CommandList->VertexBufferOffsets); + // d3d12CommandList->VertexBufferCount = 0; + // + // ZeroArray(d3d12CommandList->VertexSamplerTextures); + // ZeroArray(d3d12CommandList->VertexSamplers); + // ZeroArray(d3d12CommandList->VertexStorageTextures); + // ZeroArray(d3d12CommandList->VertexStorageBuffers); + // + // ZeroArray(d3d12CommandList->FragmentSamplerTextures); + // ZeroArray(d3d12CommandList->FragmentSamplers); + // ZeroArray(d3d12CommandList->FragmentStorageTextures); + // ZeroArray(d3d12CommandList->FragmentStorageBuffers); + } + + void D3D12_BindGraphicsPipeline(NonNullPtr commandList, NonNullPtr graphicsPipeline) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + auto pipeline = reinterpret_cast(graphicsPipeline.Get()); + + d3d12CommandList->CurrentGraphicsPipeline = pipeline; + + // Set the Descriptor heap + if (d3d12CommandList->CRB_SRV_UAV_Heap == nullptr) + { + SetDescriptorHeaps(d3d12CommandList); + } + + // Set the pipeline state + d3d12CommandList->GraphicsCommandList.CommandList->SetPipelineState(pipeline->PipelineState); + d3d12CommandList->GraphicsCommandList.CommandList->SetGraphicsRootSignature(pipeline->RootSignature->Handle); + d3d12CommandList->GraphicsCommandList.CommandList->IASetPrimitiveTopology( + JulietToD3D12_PrimitiveType[ToUnderlying(pipeline->PrimitiveType)]); + + // Mark that bindings are needed + d3d12CommandList->NeedVertexSamplerBind = true; + d3d12CommandList->NeedVertexStorageTextureBind = true; + d3d12CommandList->NeedVertexStorageBufferBind = true; + d3d12CommandList->NeedFragmentSamplerBind = true; + d3d12CommandList->NeedFragmentStorageTextureBind = true; + d3d12CommandList->NeedFragmentStorageBufferBind = true; + + for (uint32 idx = 0; idx < GPUDriver::kMaxUniformBuffersPerStage; ++idx) + { + d3d12CommandList->NeedVertexUniformBufferBind[idx] = true; + d3d12CommandList->NeedFragmentUniformBufferBind[idx] = true; + } + + for (uint32 idx = 0; idx < pipeline->VertexUniformBufferCount; ++idx) + { + // if (d3d12CommandList->VertexUniformBuffers[i] == NULL) + // { + // d3d12CommandList->VertexUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(d3d12CommandBuffer); + // } + } + + for (uint32 idx = 0; idx < pipeline->FragmentUniformBufferCount; ++idx) + { + // if (d3d12CommandList->FragmentUniformBuffers[i] == NULL) + // { + // d3d12CommandList->FragmentUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(d3d12CommandBuffer); + // } + } + + TrackGraphicsPipeline(d3d12CommandList, pipeline); + } + + void D3D12_DrawPrimitives(NonNullPtr commandList, uint32 numVertices, uint32 numInstances, + uint32 firstVertex, uint32 firstInstance) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + // TODO : Last missing piece + // D3D12_INTERNAL_BindGraphicsResources(d3d12CommandBuffer); + + d3d12CommandList->GraphicsCommandList.CommandList->DrawInstanced(numVertices, numInstances, firstVertex, firstInstance); + } + + void D3D12_DrawIndexedPrimitives(NonNullPtr commandList, uint32 numIndices, uint32 numInstances, + uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + d3d12CommandList->GraphicsCommandList.CommandList->DrawIndexedInstanced(numIndices, numInstances, firstIndex, + static_cast(vertexOffset), firstInstance); + } + // End Render Pass + + bool D3D12_AttachToWindow(NonNullPtr driver, NonNullPtr window) + { + auto* d3d12Driver = static_cast(driver.Get()); + + // TODO : Support more than one window + if (d3d12Driver->WindowData) + { + Assert(false, "D3D12 renderer already attached to the window. Right now we handle only one Window."); + return false; + } + + auto* windowData = static_cast(Calloc(1, sizeof(D3D12WindowData))); + if (!windowData) + { + Log(LogLevel::Error, LogCategory::Graphics, "OOM: D3D12WindowData"); + return false; + } + d3d12Driver->WindowData = windowData; + + windowData->Window = window; + + if (!CreateSwapChain(d3d12Driver, windowData, SwapChainComposition::SDR, PresentMode::VSync)) + { + Log(LogLevel::Error, LogCategory::Graphics, "AttachToWindow failure: Cannot create Swap Chain."); + Free(windowData); + return false; + } + + d3d12Driver->WindowData = windowData; + + return true; + } + + void D3D12_DetachFromWindow(NonNullPtr driver, NonNullPtr /*window*/) + { + auto* d3d12Driver = static_cast(driver.Get()); + auto* windowData = d3d12Driver->WindowData; + Assert(windowData && "Trying to destroy a swapchain but no Window Data exists"); + + D3D12_WaitUntilGPUIsIdle(driver); + + for (uint32 idx = 0; idx < GPUDriver::kMaxFramesInFlight; idx += 1) + { + if (windowData->InFlightFences[idx] != nullptr) { - if (driver->StagingDescriptorPools[i]) - { - DestroyStagingDescriptorPool(driver->StagingDescriptorPools[i]); - driver->StagingDescriptorPools[i] = nullptr; - } + D3D12_ReleaseFence(driver, + windowData->InFlightFences[idx] JULIET_DEBUG_PARAM(ConstString("DeatchFromWindow"))); + windowData->InFlightFences[idx] = nullptr; } + } - D3D12_DestroyDescriptorHeapPool(driver->SamplerHeapPool); + DestroySwapChain(d3d12Driver, d3d12Driver->WindowData); - // Release command buffers - for (uint32 i = 0; i < driver->AvailableCommandListCount; i += 1) + SafeFree(d3d12Driver->WindowData); + d3d12Driver->WindowData = nullptr; + } + + void DestroyDriver_Internal(NonNullPtr driver) + { + // Destroy Descriptor pools + for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) + { + if (driver->StagingDescriptorPools[i]) { - if (driver->AvailableCommandLists[i]) - { - DestroyCommandList(driver->AvailableCommandLists[i]); - driver->AvailableCommandLists[i] = nullptr; - } + DestroyStagingDescriptorPool(driver->StagingDescriptorPools[i]); + driver->StagingDescriptorPools[i] = nullptr; } + } - // Release fences - for (uint32 i = 0; i < driver->AvailableFenceCount; i += 1) + D3D12_DestroyDescriptorHeapPool(driver->SamplerHeapPool); + + // Release command buffers + for (uint32 i = 0; i < driver->AvailableCommandListCount; i += 1) + { + if (driver->AvailableCommandLists[i]) { - if (driver->AvailableFences[i]) - { - DestroyFence(driver->AvailableFences[i]); - driver->AvailableFences[i] = nullptr; - } + DestroyCommandList(driver->AvailableCommandLists[i]); + driver->AvailableCommandLists[i] = nullptr; } + } - DestroyGraphicsRootSignature(driver->BindlessRootSignature); - - DestroyDescriptorHeap(driver->BindlessDescriptorHeap); - - // Clean allocations - - SafeFree(driver->GraphicsPipelinesToDispose); - // Free(driver->WindowData); // TODO Should free the vector of WindowData, but we have only one for now - - if (driver->IndirectDrawCommandSignature) + // Release fences + for (uint32 i = 0; i < driver->AvailableFenceCount; i += 1) + { + if (driver->AvailableFences[i]) { - driver->IndirectDrawCommandSignature->Release(); - } - if (driver->IndirectIndexedDrawCommandSignature) - { - driver->IndirectIndexedDrawCommandSignature->Release(); - driver->IndirectIndexedDrawCommandSignature = nullptr; - } - if (driver->IndirectDispatchCommandSignature) - { - driver->IndirectDispatchCommandSignature->Release(); - driver->IndirectDispatchCommandSignature = nullptr; + DestroyFence(driver->AvailableFences[i]); + driver->AvailableFences[i] = nullptr; } + } - if (driver->GraphicsQueue) - { - driver->GraphicsQueue->Release(); - driver->GraphicsQueue = nullptr; - } + DestroyGraphicsRootSignature(driver->BindlessRootSignature); - if (driver->D3D12Device) - { - driver->D3D12Device->Release(); - driver->D3D12Device = nullptr; - } + DestroyDescriptorHeap(driver->BindlessDescriptorHeap); - if (driver->DXGIAdapter) - { - driver->DXGIAdapter->Release(); - driver->DXGIAdapter = nullptr; - } + // Clean allocations - if (driver->DXGIFactory) - { - driver->DXGIFactory->Release(); - driver->DXGIFactory = nullptr; - } + SafeFree(driver->GraphicsPipelinesToDispose); + // Free(driver->WindowData); // TODO Should free the vector of WindowData, but we have only one for now + + if (driver->IndirectDrawCommandSignature) + { + driver->IndirectDrawCommandSignature->Release(); + } + if (driver->IndirectIndexedDrawCommandSignature) + { + driver->IndirectIndexedDrawCommandSignature->Release(); + driver->IndirectIndexedDrawCommandSignature = nullptr; + } + if (driver->IndirectDispatchCommandSignature) + { + driver->IndirectDispatchCommandSignature->Release(); + driver->IndirectDispatchCommandSignature = nullptr; + } + + if (driver->GraphicsQueue) + { + driver->GraphicsQueue->Release(); + driver->GraphicsQueue = nullptr; + } + + if (driver->D3D12Device) + { + driver->D3D12Device->Release(); + driver->D3D12Device = nullptr; + } + + if (driver->DXGIAdapter) + { + driver->DXGIAdapter->Release(); + driver->DXGIAdapter = nullptr; + } + + if (driver->DXGIFactory) + { + driver->DXGIFactory->Release(); + driver->DXGIFactory = nullptr; + } #if JULIET_DEBUG - ShutdownDXGIDebug(driver); + ShutdownDXGIDebug(driver); #endif - if (driver->D3D12DLL) - { - UnloadDynamicLibrary(driver->D3D12DLL); - driver->D3D12DLL = nullptr; - } - - driver->D3D12SerializeVersionedRootSignatureFct = nullptr; - - ArenaRelease(driver->DriverArena); + if (driver->D3D12DLL) + { + UnloadDynamicLibrary(driver->D3D12DLL); + driver->D3D12DLL = nullptr; } - void D3D12_DestroyGraphicsDevice(NonNullPtr device) + driver->D3D12SerializeVersionedRootSignatureFct = nullptr; + + ArenaRelease(driver->DriverArena); + } + + void D3D12_DestroyGraphicsDevice(NonNullPtr device) + { + // Note: Its a down cast so clang suggest not to do it but we are totally sure about it. + auto* driver = static_cast(device->Driver); + DestroyDriver_Internal(driver); + } + + void D3D12_DestroyGraphicsPipeline(NonNullPtr driver, NonNullPtr pipeline) + { + auto* d3d12Driver = static_cast(driver.Get()); + d3d12Driver->GraphicsPipelinesToDispose[d3d12Driver->GraphicsPipelinesToDisposeCount] = + reinterpret_cast(pipeline.Get()); + d3d12Driver->GraphicsPipelinesToDisposeCount += 1; + if (d3d12Driver->GraphicsPipelinesToDisposeCount >= d3d12Driver->GraphicsPipelinesToDisposeCapacity) { - // Note: Its a down cast so clang suggest not to do it but we are totally sure about it. - auto* driver = static_cast(device->Driver); - DestroyDriver_Internal(driver); - Free(device.Get()); + ReleaseGraphicsPipeline(reinterpret_cast(pipeline.Get())); } + } - void D3D12_DestroyGraphicsPipeline(NonNullPtr driver, NonNullPtr pipeline) + void D3D12_CopyBufferToTexture(NonNullPtr commandList, NonNullPtr dst, NonNullPtr src) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + auto* d3d12TextureContainer = reinterpret_cast(dst.Get()); + auto* d3d12Texture = d3d12TextureContainer->ActiveTexture; + + TextureTransitionFromDefaultUsage(d3d12CommandList, d3d12Texture, D3D12_RESOURCE_STATE_COPY_DEST); + + // Get resource desc using C++ API + D3D12_RESOURCE_DESC desc = d3d12Texture->Resource->GetDesc(); + + D3D12_TEXTURE_COPY_LOCATION dstLoc = {}; + dstLoc.pResource = d3d12Texture->Resource; + dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dstLoc.SubresourceIndex = 0; + + // Get buffer resource - D3D12Buffer is anonymous, access Handle directly + // The GraphicsTransferBuffer IS a D3D12Buffer internally + struct D3D12TransferBuffer { - auto* d3d12Driver = static_cast(driver.Get()); - d3d12Driver->GraphicsPipelinesToDispose[d3d12Driver->GraphicsPipelinesToDisposeCount] = - reinterpret_cast(pipeline.Get()); - d3d12Driver->GraphicsPipelinesToDisposeCount += 1; - if (d3d12Driver->GraphicsPipelinesToDisposeCount >= d3d12Driver->GraphicsPipelinesToDisposeCapacity) - { - ReleaseGraphicsPipeline(reinterpret_cast(pipeline.Get())); - } - } + D3D12Descriptor Descriptor; + ID3D12Resource* Handle; + D3D12_RESOURCE_STATES CurrentState; + }; + auto* d3d12BufferSrc = reinterpret_cast(src.Get()); - void D3D12_CopyBufferToTexture(NonNullPtr commandList, NonNullPtr dst, - NonNullPtr src) - { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - auto* d3d12TextureContainer = reinterpret_cast(dst.Get()); - auto* d3d12Texture = d3d12TextureContainer->ActiveTexture; + D3D12_TEXTURE_COPY_LOCATION srcLoc = {}; + srcLoc.pResource = d3d12BufferSrc->Handle; + srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + srcLoc.PlacedFootprint.Offset = 0; + srcLoc.PlacedFootprint.Footprint.Format = desc.Format; + srcLoc.PlacedFootprint.Footprint.Width = (UINT)desc.Width; + srcLoc.PlacedFootprint.Footprint.Height = desc.Height; + srcLoc.PlacedFootprint.Footprint.Depth = 1; - TextureTransitionFromDefaultUsage(d3d12CommandList, d3d12Texture, D3D12_RESOURCE_STATE_COPY_DEST); + uint32 rowPitch = (uint32)desc.Width * 4; + rowPitch = (rowPitch + 255u) & ~255u; - // Get resource desc using C++ API - D3D12_RESOURCE_DESC desc = d3d12Texture->Resource->GetDesc(); + srcLoc.PlacedFootprint.Footprint.RowPitch = rowPitch; - D3D12_TEXTURE_COPY_LOCATION dstLoc = {}; - dstLoc.pResource = d3d12Texture->Resource; - dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - dstLoc.SubresourceIndex = 0; + d3d12CommandList->GraphicsCommandList.CommandList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr); - // Get buffer resource - D3D12Buffer is anonymous, access Handle directly - // The GraphicsTransferBuffer IS a D3D12Buffer internally - struct D3D12TransferBuffer - { - D3D12Descriptor Descriptor; - ID3D12Resource* Handle; - D3D12_RESOURCE_STATES CurrentState; - }; - auto* d3d12BufferSrc = reinterpret_cast(src.Get()); + TextureTransitionToDefaultUsage(d3d12CommandList, d3d12Texture, D3D12_RESOURCE_STATE_COPY_DEST); + } - D3D12_TEXTURE_COPY_LOCATION srcLoc = {}; - srcLoc.pResource = d3d12BufferSrc->Handle; - srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - srcLoc.PlacedFootprint.Offset = 0; - srcLoc.PlacedFootprint.Footprint.Format = desc.Format; - srcLoc.PlacedFootprint.Footprint.Width = (UINT)desc.Width; - srcLoc.PlacedFootprint.Footprint.Height = desc.Height; - srcLoc.PlacedFootprint.Footprint.Depth = 1; + uint32 D3D12_GetDescriptorIndex(NonNullPtr device, NonNullPtr buffer) + { + auto* driver = static_cast(device->Driver); + return GetDescriptorIndex(driver, buffer); + } - uint32 rowPitch = (uint32)desc.Width * 4; - rowPitch = (rowPitch + 255u) & ~255u; + uint32 D3D12_GetDescriptorIndexTexture(NonNullPtr /*device*/, NonNullPtr texture) + { + auto* textureContainer = reinterpret_cast(texture.Get()); + return textureContainer->ActiveTexture->SRVHandle.CpuHandleIndex; + } - srcLoc.PlacedFootprint.Footprint.RowPitch = rowPitch; + GraphicsDevice* D3D12_CreateGraphicsDevice(bool enableDebug) + { + Arena* driverArena = ArenaAllocate({ .Name = "D3D12 Driver Arena" }); + D3D12Driver* driver = ArenaPushStruct(driverArena JULIET_DEBUG_PARAM("D3D12Driver struct")); - d3d12CommandList->GraphicsCommandList.CommandList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr); - - TextureTransitionToDefaultUsage(d3d12CommandList, d3d12Texture, D3D12_RESOURCE_STATE_COPY_DEST); - } - - uint32 D3D12_GetDescriptorIndex(NonNullPtr device, NonNullPtr buffer) - { - auto* driver = static_cast(device->Driver); - return GetDescriptorIndex(driver, buffer); - } - - uint32 D3D12_GetDescriptorIndexTexture(NonNullPtr /*device*/, NonNullPtr texture) - { - auto* textureContainer = reinterpret_cast(texture.Get()); - return textureContainer->ActiveTexture->SRVHandle.CpuHandleIndex; - } - - GraphicsDevice* D3D12_CreateGraphicsDevice(bool enableDebug) - { - Arena* driverArena = ArenaAllocate({ .Name = "D3D12 Driver Arena" }); - D3D12Driver* driver = ArenaPushStruct(driverArena JULIET_DEBUG_PARAM("D3D12Driver struct")); - - driver->DriverArena = driverArena; + driver->DriverArena = driverArena; #if JULIET_DEBUG #ifdef IDXGIINFOQUEUE_SUPPORTED - if (enableDebug) - { - InitializeDXGIDebug(driver); - } + if (enableDebug) + { + InitializeDXGIDebug(driver); + } #endif #endif - IDXGIFactory1* factory1 = nullptr; - HRESULT result = CreateDXGIFactory1(IID_IDXGIFactory1, reinterpret_cast(&factory1)); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Assert(false, "DX12: Cannot create DXGIFactory1"); - return nullptr; - } - - result = factory1->QueryInterface(IID_IDXGIFactory4, reinterpret_cast(&driver->DXGIFactory)); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Assert(false, "DX12: Cannot create DXGIFactory4. Need DXGI1.4 support. Weird because it has been " - "checked in CheckDriver"); - return nullptr; - } - factory1->Release(); - - // Query DXGI1.5 and check for monitor Tearing support - IDXGIFactory5* factory5 = nullptr; - result = driver->DXGIFactory->QueryInterface(IID_IDXGIFactory5, reinterpret_cast(&factory5)); - if (SUCCEEDED(result)) - { - bool isTearingSupported = false; - result = factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &isTearingSupported, - sizeof(isTearingSupported)); - driver->IsTearingSupported = isTearingSupported; - if (FAILED(result)) - { - driver->IsTearingSupported = false; - } - factory5->Release(); - } - - // If available use DXGI1.6 to fetch the good graphics card. - // 1.6 should be available on most Win10 PC if they didnt their windows update. - // Lets support not having it for now... - IDXGIFactory6* factory6 = nullptr; - result = driver->DXGIFactory->QueryInterface(IID_IDXGIFactory6, reinterpret_cast(&factory6)); - if (SUCCEEDED(result)) - { - // TODO: Put into the config - static constexpr bool useLowPower = false; - result = factory6->EnumAdapterByGpuPreference(0, useLowPower ? DXGI_GPU_PREFERENCE_MINIMUM_POWER : DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, - IID_IDXGIAdapter1, reinterpret_cast(&driver->DXGIAdapter)); - factory6->Release(); - } - else - { - result = driver->DXGIFactory->EnumAdapters1(0, &driver->DXGIAdapter); - } - - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Assert(false, "Could not find adapter for D3D12Device"); - return nullptr; - } - - // Adapter is setup, get all the relevant info in the descriptor - DXGI_ADAPTER_DESC1 adapterDesc; - result = driver->DXGIAdapter->GetDesc1(&adapterDesc); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Assert(false, "Could not get DXGIAdapter description"); - return nullptr; - } - - // Driver version - LARGE_INTEGER umdVersion; - result = driver->DXGIAdapter->CheckInterfaceSupport(IID_IDXGIDevice, &umdVersion); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Assert(false, "Could not get DXGIAdapter driver version"); - return nullptr; - } - - Log(LogLevel::Message, LogCategory::Graphics, "D3D12 Driver Infos:"); - Log(LogLevel::Message, LogCategory::Graphics, "D3D12 Adapter: %S", adapterDesc.Description); - Log(LogLevel::Message, LogCategory::Graphics, "D3D12 Driver Version: %d.%d.%d.%d", HIWORD(umdVersion.HighPart), - LOWORD(umdVersion.HighPart), HIWORD(umdVersion.LowPart), LOWORD(umdVersion.LowPart)); - - driver->D3D12DLL = LoadDynamicLibrary(D3D12_DLL); - if (driver->D3D12DLL == nullptr) - { - Log(LogLevel::Error, LogCategory::Graphics, "DX12: Couldn't find " D3D12_DLL); - return nullptr; - } - - auto* D3D12CreateDeviceFuncPtr = - TOD3D12FuncPtr(PFN_D3D12_CREATE_DEVICE, LoadFunction(driver->D3D12DLL, D3D12_CREATEDEVICE_FUNC)); - if (D3D12CreateDeviceFuncPtr == nullptr) - { - Log(LogLevel::Error, LogCategory::Graphics, "DX12: Couldn't Load function " D3D12_CREATEDEVICE_FUNC " in " D3D12_DLL); - DestroyDriver_Internal(driver); - return nullptr; - } - - driver->D3D12SerializeVersionedRootSignatureFct = - TOD3D12FuncPtr(PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE, - LoadFunction(driver->D3D12DLL, D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE_FUNC)); - if (driver->D3D12SerializeVersionedRootSignatureFct == nullptr) - { - Log(LogLevel::Error, LogCategory::Graphics, - "DX12: Couldn't Load function " D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE_FUNC " in " D3D12_DLL); - DestroyDriver_Internal(driver); - return nullptr; - } - -#if JULIET_DEBUG - if (enableDebug) - { - InitializeD3D12DebugLayer(driver); - } -#endif - - result = D3D12CreateDeviceFuncPtr(static_cast(driver->DXGIAdapter), kD3DFeatureLevel, - IID_ID3D12Device5, reinterpret_cast(&driver->D3D12Device)); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create D3D12Device5"); - return nullptr; - } - - Log(LogLevel::Message, LogCategory::Graphics, "DX12: D3D12Device Created: %p", (void*)driver->D3D12Device); - -#if JULIET_DEBUG - if (enableDebug) - { - if (!InitializeD3D12DebugInfoQueue(driver)) - { - return nullptr; - } - InitializeD3D12DebugInfoLogger(driver); - } -#endif - - // Check if UMA (unified memory architecture) is available. Used on APU i think ?? - D3D12_FEATURE_DATA_ARCHITECTURE architecture; - architecture.NodeIndex = 0; - result = driver->D3D12Device->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &architecture, - sizeof(D3D12_FEATURE_DATA_ARCHITECTURE)); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not get the device architecture"); - return nullptr; - } - driver->IsUMAAvailable = architecture.UMA; - driver->IsUMACacheCoherent = architecture.CacheCoherentUMA; - - // Check "GPU Upload Heap" support (for fast uniform buffers. Not supported on my 5700xt - D3D12_FEATURE_DATA_D3D12_OPTIONS16 options16; - driver->GPUUploadHeapSupported = false; - result = driver->D3D12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS16, &options16, sizeof(options16)); - if (SUCCEEDED(result)) - { - driver->GPUUploadHeapSupported = options16.GPUUploadHeapSupported; - } - - // Create bindless root signature - driver->BindlessRootSignature = CreateGraphicsRootSignature(driver); - - // Command Queues - // Graphics Queue only for now - D3D12_COMMAND_QUEUE_DESC queueDesc = {}; - queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - queueDesc.NodeMask = 0; - queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; - result = driver->D3D12Device->CreateCommandQueue(&queueDesc, IID_ID3D12CommandQueue, - reinterpret_cast(&driver->GraphicsQueue)); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create D3D12CommandQueue: Graphics"); - return nullptr; - } - driver->GraphicsQueue->SetName(L"GRAPHICS_QUEUE"); - driver->QueueDesc[ToUnderlying(QueueType::Graphics)] = queueDesc; - - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE; - driver->QueueDesc[ToUnderlying(QueueType::Compute)] = queueDesc; - - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COPY; - driver->QueueDesc[ToUnderlying(QueueType::Copy)] = queueDesc; - - // Indirect Commands - D3D12_COMMAND_SIGNATURE_DESC commandSignatureDesc; - D3D12_INDIRECT_ARGUMENT_DESC indirectArgumentDesc; - ZeroStruct(indirectArgumentDesc); - - indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW; - commandSignatureDesc.NodeMask = 0; - commandSignatureDesc.ByteStride = sizeof(IndirectDrawCommand); - commandSignatureDesc.NumArgumentDescs = 1; - commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc; - result = driver->D3D12Device->CreateCommandSignature(&commandSignatureDesc, nullptr, IID_ID3D12CommandSignature, - reinterpret_cast(&driver->IndirectDrawCommandSignature)); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create indirect draw command signature"); - return nullptr; - } - - indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED; - commandSignatureDesc.ByteStride = sizeof(IndexedIndirectDrawCommand); - commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc; - - result = driver->D3D12Device->CreateCommandSignature(&commandSignatureDesc, nullptr, IID_ID3D12CommandSignature, - reinterpret_cast(&driver->IndirectIndexedDrawCommandSignature)); - if (FAILED(result)) - { - - DestroyDriver_Internal(driver); - Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create INDEXED Indirect draw command signature"); - return nullptr; - } - - indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH; - commandSignatureDesc.ByteStride = sizeof(IndirectDispatchCommand); - commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc; - - result = driver->D3D12Device->CreateCommandSignature(&commandSignatureDesc, nullptr, IID_ID3D12CommandSignature, - reinterpret_cast(&driver->IndirectDispatchCommandSignature)); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create Indirect dispatch command signature"); - return nullptr; - } - - // Create Pools - constexpr static size_t kMaxCommandListNumber = 16; - driver->SubmittedCommandListCapacity = kMaxCommandListNumber; - driver->SubmittedCommandListCount = 0; - driver->SubmittedCommandLists = ArenaPushArray( - driver->DriverArena, - kMaxCommandListNumber JULIET_DEBUG_PARAM("Command list Ptr Array Count: {}", kMaxCommandListNumber)); - if (!driver->SubmittedCommandLists) - { - DestroyDriver_Internal(driver); - return nullptr; - } - - constexpr static size_t kMaxFencesNumber = 16; - driver->AvailableFenceCapacity = kMaxFencesNumber; - driver->AvailableFenceCount = 0; - driver->AvailableFences = - ArenaPushArray(driver->DriverArena, - kMaxFencesNumber JULIET_DEBUG_PARAM("Fence Ptr Array Count: {}", kMaxFencesNumber)); - if (!driver->AvailableFences) - { - DestroyDriver_Internal(driver); - return nullptr; - } - - // Staging descriptor pools - for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) - { - driver->StagingDescriptorPools[i] = - CreateStagingDescriptorPool(driver, static_cast(i)); - - if (driver->StagingDescriptorPools[i] == nullptr) - { - DestroyDriver_Internal(driver); - return nullptr; - } - } - - CreateDescriptorHeapPool(driver, driver->SamplerHeapPool, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, - GPUDriver::kSampler_HeapDescriptorCount); - - // Deferred dispose vectors - driver->GraphicsPipelinesToDisposeCapacity = 4; - driver->GraphicsPipelinesToDisposeCount = 0; - driver->GraphicsPipelinesToDispose = static_cast( - Calloc(driver->GraphicsPipelinesToDisposeCapacity, sizeof(D3D12GraphicsPipeline*))); - if (!driver->GraphicsPipelinesToDispose) - { - DestroyDriver_Internal(driver); - return nullptr; - } - - driver->Semantic = WrapString("TEXCOORD"); - driver->FramesInFlight = 2; - - GraphicsDevice* device = ArenaPushStruct(driverArena JULIET_DEBUG_PARAM("GraphicsDevice")); - if (!device) - { - DestroyDriver_Internal(driver); - return nullptr; - } - - // Assign Functions to the device - device->DestroyDevice = D3D12_DestroyGraphicsDevice; - device->AttachToWindow = D3D12_AttachToWindow; - device->DetachFromWindow = D3D12_DetachFromWindow; - device->AcquireSwapChainTexture = D3D12_AcquireSwapChainTexture; - device->WaitAndAcquireSwapChainTexture = D3D12_WaitAndAcquireSwapChainTexture; - device->WaitForSwapchain = D3D12_WaitForSwapchain; - device->GetSwapChainTextureFormat = D3D12_GetSwapChainTextureFormat; - device->AcquireCommandList = D3D12_AcquireCommandList; - device->SubmitCommandLists = D3D12_SubmitCommandLists; - device->BeginRenderPass = D3D12_BeginRenderPass; - device->EndRenderPass = D3D12_EndRenderPass; - device->SetViewPort = D3D12_SetViewPort; - device->SetScissorRect = D3D12_SetScissorRect; - device->SetBlendConstants = D3D12_SetBlendConstants; - device->SetStencilReference = D3D12_SetStencilReference; - device->BindGraphicsPipeline = D3D12_BindGraphicsPipeline; - device->DrawPrimitives = D3D12_DrawPrimitives; - device->DrawIndexedPrimitives = D3D12_DrawIndexedPrimitives; - device->SetIndexBuffer = D3D12_SetIndexBuffer; - device->WaitUntilGPUIsIdle = D3D12_WaitUntilGPUIsIdle; - device->SetPushConstants = D3D12_SetPushConstants; - device->QueryFence = D3D12_QueryFence; - device->ReleaseFence = D3D12_ReleaseFence; - device->CreateShader = D3D12_CreateShader; - device->DestroyShader = D3D12_DestroyShader; - device->CreateGraphicsPipeline = D3D12_CreateGraphicsPipeline; - device->DestroyGraphicsPipeline = D3D12_DestroyGraphicsPipeline; - device->CreateGraphicsBuffer = D3D12_CreateGraphicsBuffer; - device->DestroyGraphicsBuffer = D3D12_DestroyGraphicsBuffer; - device->MapGraphicsBuffer = D3D12_MapBuffer; - device->UnmapGraphicsBuffer = D3D12_UnmapBuffer; - device->CreateGraphicsTransferBuffer = D3D12_CreateGraphicsTransferBuffer; - device->DestroyGraphicsTransferBuffer = D3D12_DestroyGraphicsTransferBuffer; - device->MapGraphicsTransferBuffer = D3D12_MapBuffer; - device->UnmapGraphicsTransferBuffer = D3D12_UnmapBuffer; - device->CopyBuffer = D3D12_CopyBuffer; - device->CopyBufferToTexture = D3D12_CopyBufferToTexture; - device->TransitionBufferToReadable = D3D12_TransitionBufferToReadable; - device->GetDescriptorIndex = D3D12_GetDescriptorIndex; - device->GetDescriptorIndexTexture = D3D12_GetDescriptorIndexTexture; - device->CreateTexture = D3D12_CreateTexture; - device->DestroyTexture = D3D12_DestroyTexture; - -#if ALLOW_SHADER_HOT_RELOAD - device->UpdateGraphicsPipelineShaders = D3D12_UpdateGraphicsPipelineShaders; -#endif - - device->Driver = driver; - device->DebugEnabled = enableDebug; - - driver->GraphicsDevice = device; - - // Create Global Bindless Heap that stays alive for the driver whole lifetime - driver->BindlessDescriptorHeap = CreateDescriptorHeap(driver, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, - GPUDriver::kCBV_SRV_UAV_HeapDescriptorCount, false); - - return device; + IDXGIFactory1* factory1 = nullptr; + HRESULT result = CreateDXGIFactory1(IID_IDXGIFactory1, reinterpret_cast(&factory1)); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Assert(false, "DX12: Cannot create DXGIFactory1"); + return nullptr; } - } // namespace + result = factory1->QueryInterface(IID_IDXGIFactory4, reinterpret_cast(&driver->DXGIFactory)); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Assert(false, "DX12: Cannot create DXGIFactory4. Need DXGI1.4 support. Weird because it has been " + "checked in CheckDriver"); + return nullptr; + } + factory1->Release(); - // clang-format off - GraphicsDeviceFactory DX12DeviceFactory = { - .Name="DirectX12", - .Type=DriverType::DX12, - .CheckDriver = D3D12_CheckDriver, - .CreateGraphicsDevice = D3D12_CreateGraphicsDevice }; - // clang-format on + // Query DXGI1.5 and check for monitor Tearing support + IDXGIFactory5* factory5 = nullptr; + result = driver->DXGIFactory->QueryInterface(IID_IDXGIFactory5, reinterpret_cast(&factory5)); + if (SUCCEEDED(result)) + { + bool isTearingSupported = false; + result = factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &isTearingSupported, + sizeof(isTearingSupported)); + driver->IsTearingSupported = isTearingSupported; + if (FAILED(result)) + { + driver->IsTearingSupported = false; + } + factory5->Release(); + } -} // namespace Juliet + // If available use DXGI1.6 to fetch the good graphics card. + // 1.6 should be available on most Win10 PC if they didnt their windows update. + // Lets support not having it for now... + IDXGIFactory6* factory6 = nullptr; + result = driver->DXGIFactory->QueryInterface(IID_IDXGIFactory6, reinterpret_cast(&factory6)); + if (SUCCEEDED(result)) + { + // TODO: Put into the config + static constexpr bool useLowPower = false; + result = factory6->EnumAdapterByGpuPreference(0, useLowPower ? DXGI_GPU_PREFERENCE_MINIMUM_POWER : DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, + IID_IDXGIAdapter1, reinterpret_cast(&driver->DXGIAdapter)); + factory6->Release(); + } + else + { + result = driver->DXGIFactory->EnumAdapters1(0, &driver->DXGIAdapter); + } + + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Assert(false, "Could not find adapter for D3D12Device"); + return nullptr; + } + + // Adapter is setup, get all the relevant info in the descriptor + DXGI_ADAPTER_DESC1 adapterDesc; + result = driver->DXGIAdapter->GetDesc1(&adapterDesc); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Assert(false, "Could not get DXGIAdapter description"); + return nullptr; + } + + // Driver version + LARGE_INTEGER umdVersion; + result = driver->DXGIAdapter->CheckInterfaceSupport(IID_IDXGIDevice, &umdVersion); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Assert(false, "Could not get DXGIAdapter driver version"); + return nullptr; + } + + Log(LogLevel::Message, LogCategory::Graphics, "D3D12 Driver Infos:"); + Log(LogLevel::Message, LogCategory::Graphics, "D3D12 Adapter: %S", adapterDesc.Description); + Log(LogLevel::Message, LogCategory::Graphics, "D3D12 Driver Version: %d.%d.%d.%d", HIWORD(umdVersion.HighPart), + LOWORD(umdVersion.HighPart), HIWORD(umdVersion.LowPart), LOWORD(umdVersion.LowPart)); + + driver->D3D12DLL = LoadDynamicLibrary(D3D12_DLL); + if (driver->D3D12DLL == nullptr) + { + Log(LogLevel::Error, LogCategory::Graphics, "DX12: Couldn't find " D3D12_DLL); + return nullptr; + } + + auto* D3D12CreateDeviceFuncPtr = + TOD3D12FuncPtr(PFN_D3D12_CREATE_DEVICE, LoadFunction(driver->D3D12DLL, D3D12_CREATEDEVICE_FUNC)); + if (D3D12CreateDeviceFuncPtr == nullptr) + { + Log(LogLevel::Error, LogCategory::Graphics, "DX12: Couldn't Load function " D3D12_CREATEDEVICE_FUNC " in " D3D12_DLL); + DestroyDriver_Internal(driver); + return nullptr; + } + + driver->D3D12SerializeVersionedRootSignatureFct = + TOD3D12FuncPtr(PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE, + LoadFunction(driver->D3D12DLL, D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE_FUNC)); + if (driver->D3D12SerializeVersionedRootSignatureFct == nullptr) + { + Log(LogLevel::Error, LogCategory::Graphics, + "DX12: Couldn't Load function " D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE_FUNC " in " D3D12_DLL); + DestroyDriver_Internal(driver); + return nullptr; + } + +#if JULIET_DEBUG + if (enableDebug) + { + InitializeD3D12DebugLayer(driver); + } +#endif + + result = D3D12CreateDeviceFuncPtr(static_cast(driver->DXGIAdapter), kD3DFeatureLevel, + IID_ID3D12Device5, reinterpret_cast(&driver->D3D12Device)); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create D3D12Device5"); + return nullptr; + } + + Log(LogLevel::Message, LogCategory::Graphics, "DX12: D3D12Device Created: %p", (void*)driver->D3D12Device); + +#if JULIET_DEBUG + if (enableDebug) + { + if (!InitializeD3D12DebugInfoQueue(driver)) + { + return nullptr; + } + InitializeD3D12DebugInfoLogger(driver); + } +#endif + + // Check if UMA (unified memory architecture) is available. Used on APU i think ?? + D3D12_FEATURE_DATA_ARCHITECTURE architecture; + architecture.NodeIndex = 0; + result = driver->D3D12Device->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &architecture, + sizeof(D3D12_FEATURE_DATA_ARCHITECTURE)); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not get the device architecture"); + return nullptr; + } + driver->IsUMAAvailable = architecture.UMA; + driver->IsUMACacheCoherent = architecture.CacheCoherentUMA; + + // Check "GPU Upload Heap" support (for fast uniform buffers. Not supported on my 5700xt + D3D12_FEATURE_DATA_D3D12_OPTIONS16 options16; + driver->GPUUploadHeapSupported = false; + result = driver->D3D12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS16, &options16, sizeof(options16)); + if (SUCCEEDED(result)) + { + driver->GPUUploadHeapSupported = options16.GPUUploadHeapSupported; + } + + // Create bindless root signature + driver->BindlessRootSignature = CreateGraphicsRootSignature(driver); + + // Command Queues + // Graphics Queue only for now + D3D12_COMMAND_QUEUE_DESC queueDesc = {}; + queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; + queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + queueDesc.NodeMask = 0; + queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; + result = driver->D3D12Device->CreateCommandQueue(&queueDesc, IID_ID3D12CommandQueue, + reinterpret_cast(&driver->GraphicsQueue)); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create D3D12CommandQueue: Graphics"); + return nullptr; + } + driver->GraphicsQueue->SetName(L"GRAPHICS_QUEUE"); + driver->QueueDesc[ToUnderlying(QueueType::Graphics)] = queueDesc; + + queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE; + driver->QueueDesc[ToUnderlying(QueueType::Compute)] = queueDesc; + + queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COPY; + driver->QueueDesc[ToUnderlying(QueueType::Copy)] = queueDesc; + + // Indirect Commands + D3D12_COMMAND_SIGNATURE_DESC commandSignatureDesc; + D3D12_INDIRECT_ARGUMENT_DESC indirectArgumentDesc; + ZeroStruct(indirectArgumentDesc); + + indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW; + commandSignatureDesc.NodeMask = 0; + commandSignatureDesc.ByteStride = sizeof(IndirectDrawCommand); + commandSignatureDesc.NumArgumentDescs = 1; + commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc; + result = driver->D3D12Device->CreateCommandSignature(&commandSignatureDesc, nullptr, IID_ID3D12CommandSignature, + reinterpret_cast(&driver->IndirectDrawCommandSignature)); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create indirect draw command signature"); + return nullptr; + } + + indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED; + commandSignatureDesc.ByteStride = sizeof(IndexedIndirectDrawCommand); + commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc; + + result = driver->D3D12Device->CreateCommandSignature(&commandSignatureDesc, nullptr, IID_ID3D12CommandSignature, + reinterpret_cast(&driver->IndirectIndexedDrawCommandSignature)); + if (FAILED(result)) + { + + DestroyDriver_Internal(driver); + Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create INDEXED Indirect draw command signature"); + return nullptr; + } + + indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH; + commandSignatureDesc.ByteStride = sizeof(IndirectDispatchCommand); + commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc; + + result = driver->D3D12Device->CreateCommandSignature(&commandSignatureDesc, nullptr, IID_ID3D12CommandSignature, + reinterpret_cast(&driver->IndirectDispatchCommandSignature)); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create Indirect dispatch command signature"); + return nullptr; + } + + // Create Pools + constexpr static size_t kMaxCommandListNumber = 16; + driver->SubmittedCommandListCapacity = kMaxCommandListNumber; + driver->SubmittedCommandListCount = 0; + driver->SubmittedCommandLists = ArenaPushArray( + driver->DriverArena, kMaxCommandListNumber JULIET_DEBUG_PARAM("Command list Ptr Array Count: {}", kMaxCommandListNumber)); + if (!driver->SubmittedCommandLists) + { + DestroyDriver_Internal(driver); + return nullptr; + } + + constexpr static size_t kMaxFencesNumber = 16; + driver->AvailableFenceCapacity = kMaxFencesNumber; + driver->AvailableFenceCount = 0; + driver->AvailableFences = + ArenaPushArray(driver->DriverArena, + kMaxFencesNumber JULIET_DEBUG_PARAM("Fence Ptr Array Count: {}", kMaxFencesNumber)); + if (!driver->AvailableFences) + { + DestroyDriver_Internal(driver); + return nullptr; + } + + // Staging descriptor pools + for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) + { + driver->StagingDescriptorPools[i] = CreateStagingDescriptorPool(driver, static_cast(i)); + + if (driver->StagingDescriptorPools[i] == nullptr) + { + DestroyDriver_Internal(driver); + return nullptr; + } + } + + CreateDescriptorHeapPool(driver, driver->SamplerHeapPool, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, + GPUDriver::kSampler_HeapDescriptorCount); + + // Deferred dispose vectors + driver->GraphicsPipelinesToDisposeCapacity = 4; + driver->GraphicsPipelinesToDisposeCount = 0; + driver->GraphicsPipelinesToDispose = static_cast( + Calloc(driver->GraphicsPipelinesToDisposeCapacity, sizeof(D3D12GraphicsPipeline*))); + if (!driver->GraphicsPipelinesToDispose) + { + DestroyDriver_Internal(driver); + return nullptr; + } + + driver->Semantic = WrapString("TEXCOORD"); + driver->FramesInFlight = 2; + + GraphicsDevice* device = ArenaPushStruct(driverArena JULIET_DEBUG_PARAM("GraphicsDevice")); + if (!device) + { + DestroyDriver_Internal(driver); + return nullptr; + } + + // Assign Functions to the device + device->DestroyDevice = D3D12_DestroyGraphicsDevice; + device->AttachToWindow = D3D12_AttachToWindow; + device->DetachFromWindow = D3D12_DetachFromWindow; + device->AcquireSwapChainTexture = D3D12_AcquireSwapChainTexture; + device->WaitAndAcquireSwapChainTexture = D3D12_WaitAndAcquireSwapChainTexture; + device->WaitForSwapchain = D3D12_WaitForSwapchain; + device->GetSwapChainTextureFormat = D3D12_GetSwapChainTextureFormat; + device->AcquireCommandList = D3D12_AcquireCommandList; + device->SubmitCommandLists = D3D12_SubmitCommandLists; + device->BeginRenderPass = D3D12_BeginRenderPass; + device->EndRenderPass = D3D12_EndRenderPass; + device->SetViewPort = D3D12_SetViewPort; + device->SetScissorRect = D3D12_SetScissorRect; + device->SetBlendConstants = D3D12_SetBlendConstants; + device->SetStencilReference = D3D12_SetStencilReference; + device->BindGraphicsPipeline = D3D12_BindGraphicsPipeline; + device->DrawPrimitives = D3D12_DrawPrimitives; + device->DrawIndexedPrimitives = D3D12_DrawIndexedPrimitives; + device->SetIndexBuffer = D3D12_SetIndexBuffer; + device->WaitUntilGPUIsIdle = D3D12_WaitUntilGPUIsIdle; + device->SetPushConstants = D3D12_SetPushConstants; + device->QueryFence = D3D12_QueryFence; + device->ReleaseFence = D3D12_ReleaseFence; + device->CreateShader = D3D12_CreateShader; + device->DestroyShader = D3D12_DestroyShader; + device->CreateGraphicsPipeline = D3D12_CreateGraphicsPipeline; + device->DestroyGraphicsPipeline = D3D12_DestroyGraphicsPipeline; + device->CreateGraphicsBuffer = D3D12_CreateGraphicsBuffer; + device->DestroyGraphicsBuffer = D3D12_DestroyGraphicsBuffer; + device->MapGraphicsBuffer = D3D12_MapBuffer; + device->UnmapGraphicsBuffer = D3D12_UnmapBuffer; + device->CreateGraphicsTransferBuffer = D3D12_CreateGraphicsTransferBuffer; + device->DestroyGraphicsTransferBuffer = D3D12_DestroyGraphicsTransferBuffer; + device->MapGraphicsTransferBuffer = D3D12_MapBuffer; + device->UnmapGraphicsTransferBuffer = D3D12_UnmapBuffer; + device->CopyBuffer = D3D12_CopyBuffer; + device->CopyBufferToTexture = D3D12_CopyBufferToTexture; + device->TransitionBufferToReadable = D3D12_TransitionBufferToReadable; + device->GetDescriptorIndex = D3D12_GetDescriptorIndex; + device->GetDescriptorIndexTexture = D3D12_GetDescriptorIndexTexture; + device->CreateTexture = D3D12_CreateTexture; + device->DestroyTexture = D3D12_DestroyTexture; + +#if ALLOW_SHADER_HOT_RELOAD + device->UpdateGraphicsPipelineShaders = D3D12_UpdateGraphicsPipelineShaders; +#endif + + device->Driver = driver; + device->DebugEnabled = enableDebug; + + driver->GraphicsDevice = device; + + // Create Global Bindless Heap that stays alive for the driver whole lifetime + driver->BindlessDescriptorHeap = CreateDescriptorHeap(driver, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, + GPUDriver::kCBV_SRV_UAV_HeapDescriptorCount, false); + + return device; + } + +} // namespace + +// clang-format off +GraphicsDeviceFactory DX12DeviceFactory = { + .Name="DirectX12", + .Type=GraphicsDriverType::DX12, + .CheckDriver = D3D12_CheckDriver, + .CreateGraphicsDevice = D3D12_CreateGraphicsDevice }; +// clang-format on diff --git a/Juliet/src/Graphics/DebugDisplayRenderer.cpp b/Juliet/src/Graphics/DebugDisplayRenderer.cpp index 217c92d..f957e4d 100644 --- a/Juliet/src/Graphics/DebugDisplayRenderer.cpp +++ b/Juliet/src/Graphics/DebugDisplayRenderer.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -7,357 +7,354 @@ #include #include -namespace Juliet +namespace { - namespace + constexpr uint32 kMaxDebugVertices = 16384; // 16K vertices = ~450KB per buffer + + struct DebugVertex { - constexpr uint32 kMaxDebugVertices = 16384; // 16K vertices = ~450KB per buffer + Vector3 Position; + FColor Color; + }; - struct DebugVertex - { - Vector3 Position; - FColor Color; - }; - - struct DebugDisplayState - { - GraphicsDevice* Device; - - // Pipelines - GraphicsPipeline* DepthTestedPipeline; - GraphicsPipeline* OverlayPipeline; - - // Vertex data (CPU side - single array with two regions) - DebugVertex* Vertices; // Single allocation for all vertices - uint32 DepthTestedVertexCount; - uint32 OverlayVertexCount; - - // GPU buffers (consolidated - single buffer pair) - GraphicsBuffer* VertexBuffer; - GraphicsTransferBuffer* TransferBuffer; - - bool Initialized; - }; - - DebugDisplayState g_DebugState = {}; - - void AddLine(DebugVertex* vertices, uint32& count, const Vector3& start, const Vector3& end, const FColor& color) - { - if (count + 2 > kMaxDebugVertices) - { - return; - } - - vertices[count++] = { start, color }; - vertices[count++] = { end, color }; - } - - void AddSphereWireframe(DebugVertex* vertices, uint32& count, const Vector3& center, float radius, const FColor& color) - { - constexpr int segments = 16; - constexpr float pi = 3.14159265358979f; - - // Draw 3 circles (XY, XZ, YZ planes) - for (int i = 0; i < segments; ++i) - { - float a1 = (float)i / segments * 2.0f * pi; - float a2 = (float)(i + 1) / segments * 2.0f * pi; - - // XY circle - Vector3 p1 = { center.x + cosf(a1) * radius, center.y + sinf(a1) * radius, center.z }; - Vector3 p2 = { center.x + cosf(a2) * radius, center.y + sinf(a2) * radius, center.z }; - AddLine(vertices, count, p1, p2, color); - - // XZ circle - p1 = { center.x + cosf(a1) * radius, center.y, center.z + sinf(a1) * radius }; - p2 = { center.x + cosf(a2) * radius, center.y, center.z + sinf(a2) * radius }; - AddLine(vertices, count, p1, p2, color); - - // YZ circle - p1 = { center.x, center.y + cosf(a1) * radius, center.z + sinf(a1) * radius }; - p2 = { center.x, center.y + cosf(a2) * radius, center.z + sinf(a2) * radius }; - AddLine(vertices, count, p1, p2, color); - } - } - - GraphicsPipeline* CreateDebugPipeline(GraphicsDevice* device, TextureFormat colorFormat, bool enableDepthTest) - { - String entryPoint = WrapString("main"); - ShaderCreateInfo shaderCI = {}; - shaderCI.EntryPoint = entryPoint; - - TempArena path = scratch_begin(0, 0); - - String vertPath = GetAssetPath(path.Arena, WrapString("Debug.vert.dxil")); - shaderCI.Stage = ShaderStage::Vertex; - Shader* vertexShader = CreateShader(device, vertPath, shaderCI); - - String fragPath = GetAssetPath(path.Arena, WrapString("Debug.frag.dxil")); - shaderCI.Stage = ShaderStage::Fragment; - Shader* fragmentShader = CreateShader(device, fragPath, shaderCI); - - scratch_end(path); - - if (!vertexShader || !fragmentShader) - { - LogError(LogCategory::Graphics, "Failed to create debug shaders"); - if (vertexShader) - { - DestroyShader(device, vertexShader); - } - if (fragmentShader) - { - DestroyShader(device, fragmentShader); - } - return nullptr; - } - - ColorTargetDescription colorDesc = {}; - colorDesc.Format = colorFormat; - - GraphicsPipelineCreateInfo createInfo = {}; - createInfo.VertexShader = vertexShader; - createInfo.FragmentShader = fragmentShader; - createInfo.PrimitiveType = PrimitiveType::LineList; - createInfo.RasterizerState.FillMode = FillMode::Solid; - createInfo.RasterizerState.CullMode = CullMode::None; - createInfo.RasterizerState.FrontFace = FrontFace::CounterClockwise; - createInfo.MultisampleState.SampleCount = TextureSampleCount::One; - - // No vertex input state - using bindless buffer access via SV_VertexID - - createInfo.TargetInfo.ColorTargetDescriptions = &colorDesc; - createInfo.TargetInfo.NumColorTargets = 1; - - // Now that we support depth-stencil targets in the backend, we can enable them. - createInfo.TargetInfo.HasDepthStencilTarget = true; - createInfo.TargetInfo.DepthStencilFormat = TextureFormat::D32_FLOAT; - - if (enableDepthTest) - { - createInfo.DepthStencilState.EnableDepthTest = true; - createInfo.DepthStencilState.EnableDepthWrite = true; - createInfo.DepthStencilState.CompareOperation = CompareOperation::Less; - } - else - { - // Overlay pipeline: depth test/write off, so it draws on top - createInfo.DepthStencilState.EnableDepthTest = false; - createInfo.DepthStencilState.EnableDepthWrite = false; - createInfo.DepthStencilState.CompareOperation = CompareOperation::Always; - } - - GraphicsPipeline* pipeline = CreateGraphicsPipeline(device, createInfo); - - DestroyShader(device, vertexShader); - DestroyShader(device, fragmentShader); - - return pipeline; - } - } // namespace - - void DebugDisplay_Initialize(NonNullPtr arena, GraphicsDevice* device) + struct DebugDisplayState { - if (g_DebugState.Initialized) + GraphicsDevice* Device; + + // Pipelines + GraphicsPipeline* DepthTestedPipeline; + GraphicsPipeline* OverlayPipeline; + + // Vertex data (CPU side - single array with two regions) + DebugVertex* Vertices; // Single allocation for all vertices + uint32 DepthTestedVertexCount; + uint32 OverlayVertexCount; + + // GPU buffers (consolidated - single buffer pair) + GraphicsBuffer* VertexBuffer; + GraphicsTransferBuffer* TransferBuffer; + + bool Initialized; + }; + + DebugDisplayState g_DebugState = {}; + + void AddLine(DebugVertex* vertices, uint32& count, const Vector3& start, const Vector3& end, const FColor& color) + { + if (count + 2 > kMaxDebugVertices) { return; } - g_DebugState.Device = device; - - // Allocate single CPU vertex array (depth-tested in first half, overlay in second half) - g_DebugState.Vertices = - ArenaPushArray(arena, kMaxDebugVertices JULIET_DEBUG_PARAM("Debug Display Renderer Vertices")); - g_DebugState.DepthTestedVertexCount = 0; - g_DebugState.OverlayVertexCount = 0; - - // Create single GPU buffer pair (consolidated) - BufferCreateInfo bufferCI = {}; - bufferCI.Size = kMaxDebugVertices * sizeof(DebugVertex); - bufferCI.Usage = BufferUsage::StructuredBuffer; - - g_DebugState.VertexBuffer = CreateGraphicsBuffer(device, bufferCI); - - TransferBufferCreateInfo transferCI = {}; - transferCI.Size = kMaxDebugVertices * sizeof(DebugVertex); - transferCI.Usage = TransferBufferUsage::Upload; - - g_DebugState.TransferBuffer = CreateGraphicsTransferBuffer(device, transferCI); - - g_DebugState.Initialized = true; + vertices[count++] = { start, color }; + vertices[count++] = { end, color }; } - void DebugDisplay_Shutdown(GraphicsDevice* device) + void AddSphereWireframe(DebugVertex* vertices, uint32& count, const Vector3& center, float radius, const FColor& color) { - if (!g_DebugState.Initialized) - { - return; - } + constexpr int segments = 16; + constexpr float pi = 3.14159265358979f; - if (g_DebugState.DepthTestedPipeline) + // Draw 3 circles (XY, XZ, YZ planes) + for (int i = 0; i < segments; ++i) { - DestroyGraphicsPipeline(device, g_DebugState.DepthTestedPipeline); - } - if (g_DebugState.OverlayPipeline) - { - DestroyGraphicsPipeline(device, g_DebugState.OverlayPipeline); - } + float a1 = (float)i / segments * 2.0f * pi; + float a2 = (float)(i + 1) / segments * 2.0f * pi; - if (g_DebugState.VertexBuffer) - { - DestroyGraphicsBuffer(device, g_DebugState.VertexBuffer); - } - if (g_DebugState.TransferBuffer) - { - DestroyGraphicsTransferBuffer(device, g_DebugState.TransferBuffer); - } + // XY circle + Vector3 p1 = { center.x + cosf(a1) * radius, center.y + sinf(a1) * radius, center.z }; + Vector3 p2 = { center.x + cosf(a2) * radius, center.y + sinf(a2) * radius, center.z }; + AddLine(vertices, count, p1, p2, color); - g_DebugState = {}; + // XZ circle + p1 = { center.x + cosf(a1) * radius, center.y, center.z + sinf(a1) * radius }; + p2 = { center.x + cosf(a2) * radius, center.y, center.z + sinf(a2) * radius }; + AddLine(vertices, count, p1, p2, color); + + // YZ circle + p1 = { center.x, center.y + cosf(a1) * radius, center.z + sinf(a1) * radius }; + p2 = { center.x, center.y + cosf(a2) * radius, center.z + sinf(a2) * radius }; + AddLine(vertices, count, p1, p2, color); + } } - void DebugDisplay_DrawLine(const Vector3& start, const Vector3& end, const FColor& color, bool overlay) + GraphicsPipeline* CreateDebugPipeline(GraphicsDevice* device, TextureFormat colorFormat, bool enableDepthTest) { - // Depth-tested vertices at beginning, overlay vertices at end (growing backward) - if (overlay) + String entryPoint = WrapString("main"); + ShaderCreateInfo shaderCI = {}; + shaderCI.EntryPoint = entryPoint; + + TempArena path = scratch_begin(0, 0); + + String vertPath = GetAssetPath(path.Arena, WrapString("Debug.vert.dxil")); + shaderCI.Stage = ShaderStage::Vertex; + Shader* vertexShader = CreateShader(device, vertPath, shaderCI); + + String fragPath = GetAssetPath(path.Arena, WrapString("Debug.frag.dxil")); + shaderCI.Stage = ShaderStage::Fragment; + Shader* fragmentShader = CreateShader(device, fragPath, shaderCI); + + scratch_end(path); + + if (!vertexShader || !fragmentShader) { - // Overlay vertices grow from end of buffer backward - uint32 halfMax = kMaxDebugVertices / 2; - AddLine(g_DebugState.Vertices + halfMax, g_DebugState.OverlayVertexCount, start, end, color); + LogError(LogCategory::Graphics, "Failed to create debug shaders"); + if (vertexShader) + { + DestroyShader(device, vertexShader); + } + if (fragmentShader) + { + DestroyShader(device, fragmentShader); + } + return nullptr; + } + + ColorTargetDescription colorDesc = {}; + colorDesc.Format = colorFormat; + + GraphicsPipelineCreateInfo createInfo = {}; + createInfo.VertexShader = vertexShader; + createInfo.FragmentShader = fragmentShader; + createInfo.PrimitiveType = PrimitiveType::LineList; + createInfo.RasterizerState.FillMode = FillMode::Solid; + createInfo.RasterizerState.CullMode = CullMode::None; + createInfo.RasterizerState.FrontFace = FrontFace::CounterClockwise; + createInfo.MultisampleState.SampleCount = TextureSampleCount::One; + + // No vertex input state - using bindless buffer access via SV_VertexID + + createInfo.TargetInfo.ColorTargetDescriptions = &colorDesc; + createInfo.TargetInfo.NumColorTargets = 1; + + // Now that we support depth-stencil targets in the backend, we can enable them. + createInfo.TargetInfo.HasDepthStencilTarget = true; + createInfo.TargetInfo.DepthStencilFormat = TextureFormat::D32_FLOAT; + + if (enableDepthTest) + { + createInfo.DepthStencilState.EnableDepthTest = true; + createInfo.DepthStencilState.EnableDepthWrite = true; + createInfo.DepthStencilState.CompareOperation = CompareOperation::Less; } else { - // Depth-tested vertices grow from start of buffer forward - AddLine(g_DebugState.Vertices, g_DebugState.DepthTestedVertexCount, start, end, color); + // Overlay pipeline: depth test/write off, so it draws on top + createInfo.DepthStencilState.EnableDepthTest = false; + createInfo.DepthStencilState.EnableDepthWrite = false; + createInfo.DepthStencilState.CompareOperation = CompareOperation::Always; } - } - void DebugDisplay_DrawSphere(const Vector3& center, float radius, const FColor& color, bool overlay) + GraphicsPipeline* pipeline = CreateGraphicsPipeline(device, createInfo); + + DestroyShader(device, vertexShader); + DestroyShader(device, fragmentShader); + + return pipeline; + } +} // namespace + +void DebugDisplay_Initialize(NonNullPtr arena, GraphicsDevice* device) +{ + if (g_DebugState.Initialized) { - if (overlay) - { - uint32 halfMax = kMaxDebugVertices / 2; - AddSphereWireframe(g_DebugState.Vertices + halfMax, g_DebugState.OverlayVertexCount, center, radius, color); - } - else - { - AddSphereWireframe(g_DebugState.Vertices, g_DebugState.DepthTestedVertexCount, center, radius, color); - } + return; } - void DebugDisplay_Prepare(CommandList* cmdList) + g_DebugState.Device = device; + + // Allocate single CPU vertex array (depth-tested in first half, overlay in second half) + g_DebugState.Vertices = + ArenaPushArray(arena, kMaxDebugVertices JULIET_DEBUG_PARAM("Debug Display Renderer Vertices")); + g_DebugState.DepthTestedVertexCount = 0; + g_DebugState.OverlayVertexCount = 0; + + // Create single GPU buffer pair (consolidated) + BufferCreateInfo bufferCI = {}; + bufferCI.Size = kMaxDebugVertices * sizeof(DebugVertex); + bufferCI.Usage = BufferUsage::StructuredBuffer; + + g_DebugState.VertexBuffer = CreateGraphicsBuffer(device, bufferCI); + + TransferBufferCreateInfo transferCI = {}; + transferCI.Size = kMaxDebugVertices * sizeof(DebugVertex); + transferCI.Usage = TransferBufferUsage::Upload; + + g_DebugState.TransferBuffer = CreateGraphicsTransferBuffer(device, transferCI); + + g_DebugState.Initialized = true; +} + +void DebugDisplay_Shutdown(GraphicsDevice* device) +{ + if (!g_DebugState.Initialized) { - if (!g_DebugState.Initialized) - { - return; - } - - uint32 totalVertices = g_DebugState.DepthTestedVertexCount + g_DebugState.OverlayVertexCount; - if (totalVertices == 0 || !g_DebugState.VertexBuffer) - { - return; - } - - // Upload all vertex data in one copy (depth-tested at start, overlay at kMaxDebugVertices/2) - void* ptr = MapGraphicsTransferBuffer(g_DebugState.Device, g_DebugState.TransferBuffer); - if (ptr) - { - // Copy depth-tested vertices (at start) - if (g_DebugState.DepthTestedVertexCount > 0) - { - MemCopy(ptr, g_DebugState.Vertices, g_DebugState.DepthTestedVertexCount * sizeof(DebugVertex)); - } - // Copy overlay vertices (at kMaxDebugVertices/2 offset) - if (g_DebugState.OverlayVertexCount > 0) - { - uint32 halfMax = kMaxDebugVertices / 2; - auto* overlayDest = static_cast(ptr) + halfMax * sizeof(DebugVertex); - auto* overlaySrc = g_DebugState.Vertices + halfMax; - MemCopy(overlayDest, overlaySrc, g_DebugState.OverlayVertexCount * sizeof(DebugVertex)); - } - UnmapGraphicsTransferBuffer(g_DebugState.Device, g_DebugState.TransferBuffer); - - // Single buffer copy (full buffer to ensure both regions are uploaded) - size_t copySize = kMaxDebugVertices * sizeof(DebugVertex); - CopyBuffer(cmdList, g_DebugState.VertexBuffer, g_DebugState.TransferBuffer, copySize); - TransitionBufferToReadable(cmdList, g_DebugState.VertexBuffer); - } + return; } - void DebugDisplay_Flush(CommandList* cmdList, RenderPass* renderPass, const Camera& camera) + if (g_DebugState.DepthTestedPipeline) { - if (!g_DebugState.Initialized) - { - return; - } - - // Lazy-create pipelines (need swapchain format) - if (!g_DebugState.DepthTestedPipeline) - { - // Use B8G8R8A8_UNORM which matches the SDR swapchain - g_DebugState.DepthTestedPipeline = CreateDebugPipeline(g_DebugState.Device, TextureFormat::B8G8R8A8_UNORM, true); - g_DebugState.OverlayPipeline = CreateDebugPipeline(g_DebugState.Device, TextureFormat::B8G8R8A8_UNORM, false); - } - - uint32 bufferIndex = GetDescriptorIndex(g_DebugState.Device, g_DebugState.VertexBuffer); - - // Render depth-tested primitives (vertices at offset 0 in buffer) - if (g_DebugState.DepthTestedVertexCount > 0 && g_DebugState.DepthTestedPipeline && g_DebugState.VertexBuffer) - { - BindGraphicsPipeline(renderPass, g_DebugState.DepthTestedPipeline); - - // Pack VP matrix + buffer index into push constants - PushData pushData = {}; - pushData.ViewProjection = Camera_GetViewProjectionMatrix(camera); - pushData.MeshIndex = 0; - pushData.TransformsBufferIndex = 0; // Not used by debug shader but layout must match - pushData.BufferIndex = bufferIndex; - pushData.TextureIndex = 0; - pushData.VertexOffset = 0; // Depth-tested vertices start at 0 - pushData.Scale[0] = 1.0f; - pushData.Scale[1] = 1.0f; - pushData.Translate[0] = 0.0f; - pushData.Translate[1] = 0.0f; - - // Dummy light data as we don't light debug primitives - pushData.GlobalLightDirection = { 0, 0, -1 }; - pushData.GlobalLightColor = { 1, 1, 1 }; - pushData.GlobalAmbientIntensity = 1.0f; - - SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData); - - DrawPrimitives(renderPass, g_DebugState.DepthTestedVertexCount, 1, 0, 0); - } - - // Render overlay primitives (vertices at offset kMaxDebugVertices/2 in buffer) - if (g_DebugState.OverlayVertexCount > 0 && g_DebugState.OverlayPipeline && g_DebugState.VertexBuffer) - { - BindGraphicsPipeline(renderPass, g_DebugState.OverlayPipeline); - - // Pack VP matrix + buffer index into push constants - PushData pushData = {}; - pushData.ViewProjection = Camera_GetViewProjectionMatrix(camera); - pushData.MeshIndex = 0; - pushData.TransformsBufferIndex = 0; - pushData.BufferIndex = bufferIndex; - pushData.TextureIndex = 0; - pushData.VertexOffset = kMaxDebugVertices / 2; // Overlay vertices start at half - pushData.Scale[0] = 1.0f; - pushData.Scale[1] = 1.0f; - pushData.Translate[0] = 0.0f; - pushData.Translate[1] = 0.0f; - - // Dummy light data as we don't light debug primitives - pushData.GlobalLightDirection = { 0, 0, -1 }; - pushData.GlobalLightColor = { 1, 1, 1 }; - pushData.GlobalAmbientIntensity = 1.0f; - - SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData); - - DrawPrimitives(renderPass, g_DebugState.OverlayVertexCount, 1, 0, 0); - } - - // Clear for next frame - g_DebugState.DepthTestedVertexCount = 0; - g_DebugState.OverlayVertexCount = 0; + DestroyGraphicsPipeline(device, g_DebugState.DepthTestedPipeline); } -} // namespace Juliet + if (g_DebugState.OverlayPipeline) + { + DestroyGraphicsPipeline(device, g_DebugState.OverlayPipeline); + } + + if (g_DebugState.VertexBuffer) + { + DestroyGraphicsBuffer(device, g_DebugState.VertexBuffer); + } + if (g_DebugState.TransferBuffer) + { + DestroyGraphicsTransferBuffer(device, g_DebugState.TransferBuffer); + } + + g_DebugState = {}; +} + +void DebugDisplay_DrawLine(const Vector3& start, const Vector3& end, const FColor& color, bool overlay) +{ + // Depth-tested vertices at beginning, overlay vertices at end (growing backward) + if (overlay) + { + // Overlay vertices grow from end of buffer backward + uint32 halfMax = kMaxDebugVertices / 2; + AddLine(g_DebugState.Vertices + halfMax, g_DebugState.OverlayVertexCount, start, end, color); + } + else + { + // Depth-tested vertices grow from start of buffer forward + AddLine(g_DebugState.Vertices, g_DebugState.DepthTestedVertexCount, start, end, color); + } +} + +void DebugDisplay_DrawSphere(const Vector3& center, float radius, const FColor& color, bool overlay) +{ + if (overlay) + { + uint32 halfMax = kMaxDebugVertices / 2; + AddSphereWireframe(g_DebugState.Vertices + halfMax, g_DebugState.OverlayVertexCount, center, radius, color); + } + else + { + AddSphereWireframe(g_DebugState.Vertices, g_DebugState.DepthTestedVertexCount, center, radius, color); + } +} + +void DebugDisplay_Prepare(CommandList* cmdList) +{ + if (!g_DebugState.Initialized) + { + return; + } + + uint32 totalVertices = g_DebugState.DepthTestedVertexCount + g_DebugState.OverlayVertexCount; + if (totalVertices == 0 || !g_DebugState.VertexBuffer) + { + return; + } + + // Upload all vertex data in one copy (depth-tested at start, overlay at kMaxDebugVertices/2) + void* ptr = MapGraphicsTransferBuffer(g_DebugState.Device, g_DebugState.TransferBuffer); + if (ptr) + { + // Copy depth-tested vertices (at start) + if (g_DebugState.DepthTestedVertexCount > 0) + { + MemCopy(ptr, g_DebugState.Vertices, g_DebugState.DepthTestedVertexCount * sizeof(DebugVertex)); + } + // Copy overlay vertices (at kMaxDebugVertices/2 offset) + if (g_DebugState.OverlayVertexCount > 0) + { + uint32 halfMax = kMaxDebugVertices / 2; + auto* overlayDest = static_cast(ptr) + halfMax * sizeof(DebugVertex); + auto* overlaySrc = g_DebugState.Vertices + halfMax; + MemCopy(overlayDest, overlaySrc, g_DebugState.OverlayVertexCount * sizeof(DebugVertex)); + } + UnmapGraphicsTransferBuffer(g_DebugState.Device, g_DebugState.TransferBuffer); + + // Single buffer copy (full buffer to ensure both regions are uploaded) + size_t copySize = kMaxDebugVertices * sizeof(DebugVertex); + CopyBuffer(cmdList, g_DebugState.VertexBuffer, g_DebugState.TransferBuffer, copySize); + TransitionBufferToReadable(cmdList, g_DebugState.VertexBuffer); + } +} + +void DebugDisplay_Flush(CommandList* cmdList, RenderPass* renderPass, const Camera& camera) +{ + if (!g_DebugState.Initialized) + { + return; + } + + // Lazy-create pipelines (need swapchain format) + if (!g_DebugState.DepthTestedPipeline) + { + // Use B8G8R8A8_UNORM which matches the SDR swapchain + g_DebugState.DepthTestedPipeline = CreateDebugPipeline(g_DebugState.Device, TextureFormat::B8G8R8A8_UNORM, true); + g_DebugState.OverlayPipeline = CreateDebugPipeline(g_DebugState.Device, TextureFormat::B8G8R8A8_UNORM, false); + } + + uint32 bufferIndex = GetDescriptorIndex(g_DebugState.Device, g_DebugState.VertexBuffer); + + // Render depth-tested primitives (vertices at offset 0 in buffer) + if (g_DebugState.DepthTestedVertexCount > 0 && g_DebugState.DepthTestedPipeline && g_DebugState.VertexBuffer) + { + BindGraphicsPipeline(renderPass, g_DebugState.DepthTestedPipeline); + + // Pack VP matrix + buffer index into push constants + PushData pushData = {}; + pushData.ViewProjection = Camera_GetViewProjectionMatrix(camera); + pushData.MeshIndex = 0; + pushData.TransformsBufferIndex = 0; // Not used by debug shader but layout must match + pushData.BufferIndex = bufferIndex; + pushData.TextureIndex = 0; + pushData.VertexOffset = 0; // Depth-tested vertices start at 0 + pushData.Scale[0] = 1.0f; + pushData.Scale[1] = 1.0f; + pushData.Translate[0] = 0.0f; + pushData.Translate[1] = 0.0f; + + // Dummy light data as we don't light debug primitives + pushData.GlobalLightDirection = { 0, 0, -1 }; + pushData.GlobalLightColor = { 1, 1, 1 }; + pushData.GlobalAmbientIntensity = 1.0f; + + SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData); + + DrawPrimitives(renderPass, g_DebugState.DepthTestedVertexCount, 1, 0, 0); + } + + // Render overlay primitives (vertices at offset kMaxDebugVertices/2 in buffer) + if (g_DebugState.OverlayVertexCount > 0 && g_DebugState.OverlayPipeline && g_DebugState.VertexBuffer) + { + BindGraphicsPipeline(renderPass, g_DebugState.OverlayPipeline); + + // Pack VP matrix + buffer index into push constants + PushData pushData = {}; + pushData.ViewProjection = Camera_GetViewProjectionMatrix(camera); + pushData.MeshIndex = 0; + pushData.TransformsBufferIndex = 0; + pushData.BufferIndex = bufferIndex; + pushData.TextureIndex = 0; + pushData.VertexOffset = kMaxDebugVertices / 2; // Overlay vertices start at half + pushData.Scale[0] = 1.0f; + pushData.Scale[1] = 1.0f; + pushData.Translate[0] = 0.0f; + pushData.Translate[1] = 0.0f; + + // Dummy light data as we don't light debug primitives + pushData.GlobalLightDirection = { 0, 0, -1 }; + pushData.GlobalLightColor = { 1, 1, 1 }; + pushData.GlobalAmbientIntensity = 1.0f; + + SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData); + + DrawPrimitives(renderPass, g_DebugState.OverlayVertexCount, 1, 0, 0); + } + + // Clear for next frame + g_DebugState.DepthTestedVertexCount = 0; + g_DebugState.OverlayVertexCount = 0; +} diff --git a/Juliet/src/Graphics/Graphics.cpp b/Juliet/src/Graphics/Graphics.cpp index 37ac71b..b5eaa35 100644 --- a/Juliet/src/Graphics/Graphics.cpp +++ b/Juliet/src/Graphics/Graphics.cpp @@ -8,439 +8,436 @@ #include #include -namespace Juliet +namespace Internal::Graphics { - namespace Internal::Graphics - { - // TODO : IfDef new factories that are not compatible - // Low chance of porting on something else than windows though. May be linux but will use vulkan that works on windows - constexpr GraphicsDeviceFactory* Factories[] = { &DX12DeviceFactory }; + // TODO : IfDef new factories that are not compatible + // Low chance of porting on something else than windows though. May be linux but will use vulkan that works on windows + constexpr GraphicsDeviceFactory* Factories[] = { &DX12DeviceFactory }; - const GraphicsDeviceFactory* ChooseFactory(GraphicsConfig config) + const GraphicsDeviceFactory* ChooseFactory(GraphicsConfig config) + { + // First try to check the preferred renderer from the config if any. + if (config.PreferredDriver != GraphicsDriverType::Any) { - // First try to check the preferred renderer from the config if any. - if (config.PreferredDriver != DriverType::Any) + for (const GraphicsDeviceFactory* factory : Factories) { - for (const GraphicsDeviceFactory* factory : Factories) + // If the config has a preferred renderer, immediately pick it up. + if (factory->Type == config.PreferredDriver) { - // If the config has a preferred renderer, immediately pick it up. - if (factory->Type == config.PreferredDriver) + if (factory->CheckDriver()) { - if (factory->CheckDriver()) - { - return factory; - } + return factory; } } } - - // If not preferred renderer was set, use the first one that works in the list - for (const GraphicsDeviceFactory* factory : Factories) - { - if (factory->Type == config.PreferredDriver) - { - continue; - } - - // TODO : Make sure it's supported by querying it first. If supported -> Lets go - if (factory->CheckDriver()) - { - return factory; - } - } - - Log(LogLevel::Error, LogCategory::Graphics, "CreateGraphicsDevice::ChooseFactory: No valid driver found"); - return nullptr; } - } // namespace Internal::Graphics - GraphicsDevice* CreateGraphicsDevice(GraphicsConfig config) - { - if (const GraphicsDeviceFactory* chosenFactory = Internal::Graphics::ChooseFactory(config)) + // If not preferred renderer was set, use the first one that works in the list + for (const GraphicsDeviceFactory* factory : Factories) { - if (GraphicsDevice* newDevice = chosenFactory->CreateGraphicsDevice(config.EnableDebug)) + if (factory->Type == config.PreferredDriver) { - newDevice->Name = chosenFactory->Name; - return newDevice; + continue; + } + + // TODO : Make sure it's supported by querying it first. If supported -> Lets go + if (factory->CheckDriver()) + { + return factory; } } + + Log(LogLevel::Error, LogCategory::Graphics, "CreateGraphicsDevice::ChooseFactory: No valid driver found"); + return nullptr; + } +} // namespace Internal::Graphics + +GraphicsDevice* CreateGraphicsDevice(GraphicsConfig config) +{ + if (const GraphicsDeviceFactory* chosenFactory = Internal::Graphics::ChooseFactory(config)) + { + if (GraphicsDevice* newDevice = chosenFactory->CreateGraphicsDevice(config.EnableDebug)) + { + newDevice->Name = chosenFactory->Name; + return newDevice; + } + } + return nullptr; +} + +void DestroyGraphicsDevice(NonNullPtr device) +{ + device->DestroyDevice(device); +} + +bool AttachToWindow(NonNullPtr device, NonNullPtr window) +{ + GPUDriver* driver = device->Driver; + return device->AttachToWindow(driver, window); +} + +void DetachFromWindow(NonNullPtr device, NonNullPtr window) +{ + GPUDriver* driver = device->Driver; + device->DetachFromWindow(driver, window); +} + +bool AcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture) +{ + auto header = reinterpret_cast(commandList.Get()); + + if (header->Device->DebugEnabled) + { + bool error = false; + if (header->Submitted) + { + error = true; + Assert(false, "Cannot submit command list twice"); + } + + if (header->RenderPass.IsInProgress) + { + error = true; + Assert(false, "Cannot submit command list twice"); + } + + if (error) + { + return false; + } + } + + header->Device->AcquireSwapChainTexture(commandList, window, swapChainTexture); + if (swapChainTexture) + { + header->AcquiredSwapChain = true; + } + + return true; +} + +bool WaitAndAcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture) +{ + auto header = reinterpret_cast(commandList.Get()); + + if (header->Device->DebugEnabled) + { + bool error = false; + if (header->Submitted) + { + error = true; + Assert(false, "Cannot submit command list twice"); + } + + if (header->RenderPass.IsInProgress) + { + error = true; + Assert(false, "Cannot submit command list twice"); + } + + if (error) + { + return false; + } + } + + header->Device->WaitAndAcquireSwapChainTexture(commandList, window, swapChainTexture); + if (swapChainTexture) + { + header->AcquiredSwapChain = true; + } + + return true; +} + +bool WaitForSwapchain(NonNullPtr device, NonNullPtr window) +{ + return device->WaitForSwapchain(device->Driver, window); +} + +TextureFormat GetSwapChainTextureFormat(NonNullPtr device, NonNullPtr window) +{ + return device->GetSwapChainTextureFormat(device->Driver, window); +} + +Texture* CreateTexture(NonNullPtr device, const TextureCreateInfo& createInfo) +{ + return device->CreateTexture(device->Driver, createInfo); +} + +void DestroyTexture(NonNullPtr device, NonNullPtr texture) +{ + device->DestroyTexture(device->Driver, texture); +} + +CommandList* AcquireCommandList(NonNullPtr device, QueueType queueType /* = QueueType::Graphics */) +{ + GPUDriver* driver = device->Driver; + CommandList* cmdList = device->AcquireCommandList(driver, queueType); + if (!cmdList) + { return nullptr; } - void DestroyGraphicsDevice(NonNullPtr device) + auto header = reinterpret_cast(cmdList); + header->Device = device.Get(); + header->RenderPass.CommandList = cmdList; + header->Submitted = false; + + return cmdList; +} + +void SubmitCommandLists(NonNullPtr commandList) +{ + auto* commandListHeader = reinterpret_cast(commandList.Get()); + + commandListHeader->Submitted = true; + + commandListHeader->Device->SubmitCommandLists(commandList); +} + +RenderPass* BeginRenderPass(NonNullPtr commandList, ColorTargetInfo& colorTargetInfo, + DepthStencilTargetInfo* depthStencilTargetInfo) +{ + return BeginRenderPass(commandList, &colorTargetInfo, 1, depthStencilTargetInfo); +} + +RenderPass* BeginRenderPass(NonNullPtr commandList, NonNullPtr colorTargetInfos, + uint32 colorTargetInfoCount, DepthStencilTargetInfo* depthStencilTargetInfo) +{ + if (colorTargetInfoCount > GPUDriver::kMaxColorTargetInfo) { - device->DestroyDevice(device); + Log(LogLevel::Error, LogCategory::Graphics, "BeginRenderPass: ColorTargetInfoCount is > than kMaxColorTargetInfo"); + return nullptr; } - bool AttachToWindow(NonNullPtr device, NonNullPtr window) + auto* header = reinterpret_cast(commandList.Get()); + header->Device->BeginRenderPass(commandList, colorTargetInfos, colorTargetInfoCount, depthStencilTargetInfo); + + header->RenderPass.IsInProgress = true; + return reinterpret_cast(&header->RenderPass); +} + +void EndRenderPass(NonNullPtr renderPass) +{ + auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; + auto* commandListHeader = reinterpret_cast(commandList); + + commandListHeader->Device->EndRenderPass(commandList); + + commandListHeader->RenderPass.IsInProgress = false; +} + +void SetGraphicsViewPort(NonNullPtr renderPass, const GraphicsViewPort& viewPort) +{ + auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; + auto* commandListHeader = reinterpret_cast(commandList); + + commandListHeader->Device->SetViewPort(commandList, viewPort); +} + +void SetScissorRect(NonNullPtr renderPass, const struct Rectangle& rectangle) +{ + auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; + auto* commandListHeader = reinterpret_cast(commandList); + + commandListHeader->Device->SetScissorRect(commandList, rectangle); +} + +void SetBlendConstants(NonNullPtr renderPass, FColor blendConstants) +{ + auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; + auto* commandListHeader = reinterpret_cast(commandList); + + commandListHeader->Device->SetBlendConstants(commandList, blendConstants); +} + +void SetStencilReference(NonNullPtr renderPass, uint8 reference) +{ + auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; + auto* commandListHeader = reinterpret_cast(commandList); + + commandListHeader->Device->SetStencilReference(commandList, reference); +} + +void SetIndexBuffer(NonNullPtr commandList, NonNullPtr buffer, IndexFormat format, + size_t indexCount, index_t offset) +{ + auto* commandListHeader = reinterpret_cast(commandList.Get()); + + if (commandListHeader->Device->SetIndexBuffer) { - GPUDriver* driver = device->Driver; - return device->AttachToWindow(driver, window); + commandListHeader->Device->SetIndexBuffer(commandList, buffer, format, indexCount, offset); + } +} + +void BindGraphicsPipeline(NonNullPtr renderPass, NonNullPtr graphicsPipeline) +{ + auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; + auto* commandListHeader = reinterpret_cast(commandList); + + commandListHeader->Device->BindGraphicsPipeline(commandList, graphicsPipeline); +} + +void DrawPrimitives(NonNullPtr renderPass, uint32 numVertices, uint32 numInstances, uint32 firstVertex, uint32 firstInstance) +{ + auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; + auto* commandListHeader = reinterpret_cast(commandList); + + commandListHeader->Device->DrawPrimitives(commandList, numVertices, numInstances, firstVertex, firstInstance); +} + +void DrawIndexedPrimitives(NonNullPtr renderPass, uint32 numIndices, uint32 numInstances, + uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance) +{ + auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; + auto* commandListHeader = reinterpret_cast(commandList); + + if (commandListHeader->Device->DrawIndexedPrimitives) + { + commandListHeader->Device->DrawIndexedPrimitives(commandList, numIndices, numInstances, firstIndex, + vertexOffset, firstInstance); + } +} + +void SetPushConstants(NonNullPtr commandList, ShaderStage stage, uint32 rootParameterIndex, + uint32 numConstants, const void* constants) +{ + auto* header = reinterpret_cast(commandList.Get()); + header->Device->SetPushConstants(commandList, stage, rootParameterIndex, numConstants, constants); +} + +// Fences +bool WaitUntilGPUIsIdle(NonNullPtr device) +{ + return device->WaitUntilGPUIsIdle(device->Driver); +} + +// Shaders +Shader* CreateShader(NonNullPtr device, String filename, ShaderCreateInfo& shaderCreateInfo) +{ + TempArena fileArena = scratch_begin(0, 0); + ByteBuffer shaderByteCode = {}; + + // Create path from filename + if (IsAbsolutePath(filename)) + { + shaderByteCode = LoadFile(fileArena.Arena, filename); + } + else + { + // TODO: Add path builder in the lib + String base = GetBasePath(); + char inplaceBuffer[256]; + juliet_snprintf(inplaceBuffer, sizeof(inplaceBuffer), "%s%s", base.Str, filename.Str); + String absolutePath = WrapString(inplaceBuffer); + shaderByteCode = LoadFile(fileArena.Arena, absolutePath); } - void DetachFromWindow(NonNullPtr device, NonNullPtr window) + if (!IsValid(shaderByteCode)) { - GPUDriver* driver = device->Driver; - device->DetachFromWindow(driver, window); + return nullptr; } - bool AcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture) - { - auto header = reinterpret_cast(commandList.Get()); + Shader* shader = device->CreateShader(device->Driver, shaderByteCode, shaderCreateInfo JULIET_DEBUG_PARAM(filename)); - if (header->Device->DebugEnabled) - { - bool error = false; - if (header->Submitted) - { - error = true; - Assert(false, "Cannot submit command list twice"); - } + scratch_end(fileArena); - if (header->RenderPass.IsInProgress) - { - error = true; - Assert(false, "Cannot submit command list twice"); - } + return shader; +} - if (error) - { - return false; - } - } +void DestroyShader(NonNullPtr device, NonNullPtr shader) +{ + device->DestroyShader(device->Driver, shader); +} - header->Device->AcquireSwapChainTexture(commandList, window, swapChainTexture); - if (swapChainTexture) - { - header->AcquiredSwapChain = true; - } +GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr device, const GraphicsPipelineCreateInfo& createInfo) +{ + return device->CreateGraphicsPipeline(device->Driver, createInfo); +} - return true; - } - - bool WaitAndAcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture) - { - auto header = reinterpret_cast(commandList.Get()); - - if (header->Device->DebugEnabled) - { - bool error = false; - if (header->Submitted) - { - error = true; - Assert(false, "Cannot submit command list twice"); - } - - if (header->RenderPass.IsInProgress) - { - error = true; - Assert(false, "Cannot submit command list twice"); - } - - if (error) - { - return false; - } - } - - header->Device->WaitAndAcquireSwapChainTexture(commandList, window, swapChainTexture); - if (swapChainTexture) - { - header->AcquiredSwapChain = true; - } - - return true; - } - - bool WaitForSwapchain(NonNullPtr device, NonNullPtr window) - { - return device->WaitForSwapchain(device->Driver, window); - } - - TextureFormat GetSwapChainTextureFormat(NonNullPtr device, NonNullPtr window) - { - return device->GetSwapChainTextureFormat(device->Driver, window); - } - - Texture* CreateTexture(NonNullPtr device, const TextureCreateInfo& createInfo) - { - return device->CreateTexture(device->Driver, createInfo); - } - - void DestroyTexture(NonNullPtr device, NonNullPtr texture) - { - device->DestroyTexture(device->Driver, texture); - } - - CommandList* AcquireCommandList(NonNullPtr device, QueueType queueType /* = QueueType::Graphics */) - { - GPUDriver* driver = device->Driver; - CommandList* cmdList = device->AcquireCommandList(driver, queueType); - if (!cmdList) - { - return nullptr; - } - - auto header = reinterpret_cast(cmdList); - header->Device = device.Get(); - header->RenderPass.CommandList = cmdList; - header->Submitted = false; - - return cmdList; - } - - void SubmitCommandLists(NonNullPtr commandList) - { - auto* commandListHeader = reinterpret_cast(commandList.Get()); - - commandListHeader->Submitted = true; - - commandListHeader->Device->SubmitCommandLists(commandList); - } - - RenderPass* BeginRenderPass(NonNullPtr commandList, ColorTargetInfo& colorTargetInfo, - DepthStencilTargetInfo* depthStencilTargetInfo) - { - return BeginRenderPass(commandList, &colorTargetInfo, 1, depthStencilTargetInfo); - } - - RenderPass* BeginRenderPass(NonNullPtr commandList, NonNullPtr colorTargetInfos, - uint32 colorTargetInfoCount, DepthStencilTargetInfo* depthStencilTargetInfo) - { - if (colorTargetInfoCount > GPUDriver::kMaxColorTargetInfo) - { - Log(LogLevel::Error, LogCategory::Graphics, "BeginRenderPass: ColorTargetInfoCount is > than kMaxColorTargetInfo"); - return nullptr; - } - - auto* header = reinterpret_cast(commandList.Get()); - header->Device->BeginRenderPass(commandList, colorTargetInfos, colorTargetInfoCount, depthStencilTargetInfo); - - header->RenderPass.IsInProgress = true; - return reinterpret_cast(&header->RenderPass); - } - - void EndRenderPass(NonNullPtr renderPass) - { - auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; - auto* commandListHeader = reinterpret_cast(commandList); - - commandListHeader->Device->EndRenderPass(commandList); - - commandListHeader->RenderPass.IsInProgress = false; - } - - void SetGraphicsViewPort(NonNullPtr renderPass, const GraphicsViewPort& viewPort) - { - auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; - auto* commandListHeader = reinterpret_cast(commandList); - - commandListHeader->Device->SetViewPort(commandList, viewPort); - } - - void SetScissorRect(NonNullPtr renderPass, const Rectangle& rectangle) - { - auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; - auto* commandListHeader = reinterpret_cast(commandList); - - commandListHeader->Device->SetScissorRect(commandList, rectangle); - } - - void SetBlendConstants(NonNullPtr renderPass, FColor blendConstants) - { - auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; - auto* commandListHeader = reinterpret_cast(commandList); - - commandListHeader->Device->SetBlendConstants(commandList, blendConstants); - } - - void SetStencilReference(NonNullPtr renderPass, uint8 reference) - { - auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; - auto* commandListHeader = reinterpret_cast(commandList); - - commandListHeader->Device->SetStencilReference(commandList, reference); - } - - void SetIndexBuffer(NonNullPtr commandList, NonNullPtr buffer, IndexFormat format, - size_t indexCount, index_t offset) - { - auto* commandListHeader = reinterpret_cast(commandList.Get()); - - if (commandListHeader->Device->SetIndexBuffer) - { - commandListHeader->Device->SetIndexBuffer(commandList, buffer, format, indexCount, offset); - } - } - - void BindGraphicsPipeline(NonNullPtr renderPass, NonNullPtr graphicsPipeline) - { - auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; - auto* commandListHeader = reinterpret_cast(commandList); - - commandListHeader->Device->BindGraphicsPipeline(commandList, graphicsPipeline); - } - - void DrawPrimitives(NonNullPtr renderPass, uint32 numVertices, uint32 numInstances, uint32 firstVertex, uint32 firstInstance) - { - auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; - auto* commandListHeader = reinterpret_cast(commandList); - - commandListHeader->Device->DrawPrimitives(commandList, numVertices, numInstances, firstVertex, firstInstance); - } - - void DrawIndexedPrimitives(NonNullPtr renderPass, uint32 numIndices, uint32 numInstances, - uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance) - { - auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; - auto* commandListHeader = reinterpret_cast(commandList); - - if (commandListHeader->Device->DrawIndexedPrimitives) - { - commandListHeader->Device->DrawIndexedPrimitives(commandList, numIndices, numInstances, firstIndex, - vertexOffset, firstInstance); - } - } - - void SetPushConstants(NonNullPtr commandList, ShaderStage stage, uint32 rootParameterIndex, - uint32 numConstants, const void* constants) - { - auto* header = reinterpret_cast(commandList.Get()); - header->Device->SetPushConstants(commandList, stage, rootParameterIndex, numConstants, constants); - } - - // Fences - bool WaitUntilGPUIsIdle(NonNullPtr device) - { - return device->WaitUntilGPUIsIdle(device->Driver); - } - - // Shaders - Shader* CreateShader(NonNullPtr device, String filename, ShaderCreateInfo& shaderCreateInfo) - { - TempArena fileArena = scratch_begin(0, 0); - ByteBuffer shaderByteCode = {}; - - // Create path from filename - if (IsAbsolutePath(filename)) - { - shaderByteCode = LoadFile(fileArena.Arena, filename); - } - else - { - // TODO: Add path builder in the lib - String base = GetBasePath(); - char inplaceBuffer[256]; - juliet_snprintf(inplaceBuffer, sizeof(inplaceBuffer), "%s%s", base.Str, filename.Str); - String absolutePath = WrapString(inplaceBuffer); - shaderByteCode = LoadFile(fileArena.Arena, absolutePath); - } - - if (!IsValid(shaderByteCode)) - { - return nullptr; - } - - Shader* shader = device->CreateShader(device->Driver, shaderByteCode, shaderCreateInfo JULIET_DEBUG_PARAM(filename)); - - scratch_end(fileArena); - - return shader; - } - - void DestroyShader(NonNullPtr device, NonNullPtr shader) - { - device->DestroyShader(device->Driver, shader); - } - - GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr device, const GraphicsPipelineCreateInfo& createInfo) - { - return device->CreateGraphicsPipeline(device->Driver, createInfo); - } - - void DestroyGraphicsPipeline(NonNullPtr device, NonNullPtr graphicsPipeline) - { - device->DestroyGraphicsPipeline(device->Driver, graphicsPipeline); - } +void DestroyGraphicsPipeline(NonNullPtr device, NonNullPtr graphicsPipeline) +{ + device->DestroyGraphicsPipeline(device->Driver, graphicsPipeline); +} #if ALLOW_SHADER_HOT_RELOAD - bool UpdateGraphicsPipelineShaders(NonNullPtr device, NonNullPtr graphicsPipeline, - Shader* optional_vertexShader, Shader* optional_fragmentShader) - { - return device->UpdateGraphicsPipelineShaders(device->Driver, graphicsPipeline, optional_vertexShader, optional_fragmentShader); - } +bool UpdateGraphicsPipelineShaders(NonNullPtr device, NonNullPtr graphicsPipeline, + Shader* optional_vertexShader, Shader* optional_fragmentShader) +{ + return device->UpdateGraphicsPipelineShaders(device->Driver, graphicsPipeline, optional_vertexShader, optional_fragmentShader); +} #endif - GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr device, const BufferCreateInfo& createInfo) - { - return device->CreateGraphicsBuffer(device->Driver, createInfo.Size, createInfo.Stride, createInfo.Usage, - createInfo.IsDynamic); - } +GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr device, const BufferCreateInfo& createInfo) +{ + return device->CreateGraphicsBuffer(device->Driver, createInfo.Size, createInfo.Stride, createInfo.Usage, + createInfo.IsDynamic); +} - GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr device, const TransferBufferCreateInfo& createInfo) - { - return device->CreateGraphicsTransferBuffer(device->Driver, createInfo.Size, createInfo.Usage); - } +GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr device, const TransferBufferCreateInfo& createInfo) +{ + return device->CreateGraphicsTransferBuffer(device->Driver, createInfo.Size, createInfo.Usage); +} - void* MapGraphicsBuffer(NonNullPtr device, NonNullPtr buffer) - { - return device->MapGraphicsBuffer(device->Driver, buffer); - } +void* MapGraphicsBuffer(NonNullPtr device, NonNullPtr buffer) +{ + return device->MapGraphicsBuffer(device->Driver, buffer); +} - void UnmapGraphicsBuffer(NonNullPtr device, NonNullPtr buffer) - { - device->UnmapGraphicsBuffer(device->Driver, buffer); - } +void UnmapGraphicsBuffer(NonNullPtr device, NonNullPtr buffer) +{ + device->UnmapGraphicsBuffer(device->Driver, buffer); +} - void* MapGraphicsTransferBuffer(NonNullPtr device, NonNullPtr buffer) - { - return device->MapGraphicsTransferBuffer(device->Driver, buffer); - } +void* MapGraphicsTransferBuffer(NonNullPtr device, NonNullPtr buffer) +{ + return device->MapGraphicsTransferBuffer(device->Driver, buffer); +} - void UnmapGraphicsTransferBuffer(NonNullPtr device, NonNullPtr buffer) - { - device->UnmapGraphicsTransferBuffer(device->Driver, buffer); - } +void UnmapGraphicsTransferBuffer(NonNullPtr device, NonNullPtr buffer) +{ + device->UnmapGraphicsTransferBuffer(device->Driver, buffer); +} - void CopyBuffer(NonNullPtr commandList, NonNullPtr dst, - NonNullPtr src, size_t size, size_t dstOffset, size_t srcOffset) - { - auto* headers = reinterpret_cast(commandList.Get()); - headers->Device->CopyBuffer(commandList, dst, src, size, dstOffset, srcOffset); - } +void CopyBuffer(NonNullPtr commandList, NonNullPtr dst, + NonNullPtr src, size_t size, size_t dstOffset, size_t srcOffset) +{ + auto* headers = reinterpret_cast(commandList.Get()); + headers->Device->CopyBuffer(commandList, dst, src, size, dstOffset, srcOffset); +} - void CopyBufferToTexture(NonNullPtr commandList, NonNullPtr dst, NonNullPtr src) +void CopyBufferToTexture(NonNullPtr commandList, NonNullPtr dst, NonNullPtr src) +{ + auto* headers = reinterpret_cast(commandList.Get()); + if (headers->Device->CopyBufferToTexture) { - auto* headers = reinterpret_cast(commandList.Get()); - if (headers->Device->CopyBufferToTexture) - { - headers->Device->CopyBufferToTexture(commandList, dst, src); - } + headers->Device->CopyBufferToTexture(commandList, dst, src); } +} - void TransitionBufferToReadable(NonNullPtr commandList, NonNullPtr buffer) - { - auto* header = reinterpret_cast(commandList.Get()); - header->Device->TransitionBufferToReadable(commandList, buffer); - } +void TransitionBufferToReadable(NonNullPtr commandList, NonNullPtr buffer) +{ + auto* header = reinterpret_cast(commandList.Get()); + header->Device->TransitionBufferToReadable(commandList, buffer); +} - uint32 GetDescriptorIndex(NonNullPtr device, NonNullPtr buffer) - { - return device->GetDescriptorIndex(device, buffer); - } +uint32 GetDescriptorIndex(NonNullPtr device, NonNullPtr buffer) +{ + return device->GetDescriptorIndex(device, buffer); +} - uint32 GetDescriptorIndex(NonNullPtr device, NonNullPtr texture) - { - return device->GetDescriptorIndexTexture(device, texture); - } +uint32 GetDescriptorIndex(NonNullPtr device, NonNullPtr texture) +{ + return device->GetDescriptorIndexTexture(device, texture); +} - void DestroyGraphicsBuffer(NonNullPtr device, NonNullPtr buffer) - { - device->DestroyGraphicsBuffer(buffer); - } +void DestroyGraphicsBuffer(NonNullPtr device, NonNullPtr buffer) +{ + device->DestroyGraphicsBuffer(buffer); +} - void DestroyGraphicsTransferBuffer(NonNullPtr device, NonNullPtr buffer) - { - device->DestroyGraphicsTransferBuffer(buffer); - } -} // namespace Juliet +void DestroyGraphicsTransferBuffer(NonNullPtr device, NonNullPtr buffer) +{ + device->DestroyGraphicsTransferBuffer(buffer); +} diff --git a/Juliet/src/Graphics/GraphicsDevice.h b/Juliet/src/Graphics/GraphicsDevice.h index c031821..783c5e5 100644 --- a/Juliet/src/Graphics/GraphicsDevice.h +++ b/Juliet/src/Graphics/GraphicsDevice.h @@ -6,134 +6,131 @@ #include #include -namespace Juliet +struct TextureHeader { - struct TextureHeader - { - TextureCreateInfo CreateInfo; - }; + TextureCreateInfo CreateInfo; +}; - struct GPUPass - { - CommandList* CommandList; - bool IsInProgress : 1; - }; +struct GPUPass +{ + CommandList* CommandList; + bool IsInProgress : 1; +}; - struct CommandListHeader - { - GraphicsDevice* Device = nullptr; - bool AcquiredSwapChain = false; - bool Submitted = false; +struct CommandListHeader +{ + GraphicsDevice* Device = nullptr; + bool AcquiredSwapChain = false; + bool Submitted = false; - GPUPass RenderPass; - }; + GPUPass RenderPass; +}; - struct GPUDriver - { - Arena* DriverArena = {}; +struct GPUDriver +{ + Arena* DriverArena = {}; - static constexpr uint8 kMaxFramesInFlight = 3; - static constexpr uint8 kMaxColorTargetInfo = 4; - static constexpr uint8 kMaxUniformBuffersPerStage = 4; - static constexpr uint8 kMaxVertexBuffers = 16; + static constexpr uint8 kMaxFramesInFlight = 3; + static constexpr uint8 kMaxColorTargetInfo = 4; + static constexpr uint8 kMaxUniformBuffersPerStage = 4; + static constexpr uint8 kMaxVertexBuffers = 16; - static constexpr uint32 kCBV_SRV_UAV_HeapDescriptorCount = 65536; - static constexpr uint32 kSampler_HeapDescriptorCount = 2048; - }; + static constexpr uint32 kCBV_SRV_UAV_HeapDescriptorCount = 65536; + static constexpr uint32 kSampler_HeapDescriptorCount = 2048; +}; - struct GraphicsDevice - { - void (*DestroyDevice)(NonNullPtr self); +struct GraphicsDevice +{ + void (*DestroyDevice)(NonNullPtr self); - // Attach to window - bool (*AttachToWindow)(NonNullPtr driver, NonNullPtr window); - void (*DetachFromWindow)(NonNullPtr driver, NonNullPtr window); + // Attach to window + bool (*AttachToWindow)(NonNullPtr driver, NonNullPtr window); + void (*DetachFromWindow)(NonNullPtr driver, NonNullPtr window); - // SwapChain - bool (*AcquireSwapChainTexture)(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture); - bool (*WaitAndAcquireSwapChainTexture)(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture); - bool (*WaitForSwapchain)(NonNullPtr driver, NonNullPtr window); - TextureFormat (*GetSwapChainTextureFormat)(NonNullPtr driver, NonNullPtr window); + // SwapChain + bool (*AcquireSwapChainTexture)(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture); + bool (*WaitAndAcquireSwapChainTexture)(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture); + bool (*WaitForSwapchain)(NonNullPtr driver, NonNullPtr window); + TextureFormat (*GetSwapChainTextureFormat)(NonNullPtr driver, NonNullPtr window); - // CommandLists - CommandList* (*AcquireCommandList)(NonNullPtr driver, QueueType queueType); - bool (*SubmitCommandLists)(NonNullPtr commandList); + // CommandLists + CommandList* (*AcquireCommandList)(NonNullPtr driver, QueueType queueType); + bool (*SubmitCommandLists)(NonNullPtr commandList); - // RenderPass - void (*BeginRenderPass)(NonNullPtr commandList, NonNullPtr colorTargetInfos, - uint32 colorTargetInfoCount, const DepthStencilTargetInfo* depthStencilTargetInfo); - void (*EndRenderPass)(NonNullPtr commandList); + // RenderPass + void (*BeginRenderPass)(NonNullPtr commandList, NonNullPtr colorTargetInfos, + uint32 colorTargetInfoCount, const DepthStencilTargetInfo* depthStencilTargetInfo); + void (*EndRenderPass)(NonNullPtr commandList); - void (*SetViewPort)(NonNullPtr commandList, const GraphicsViewPort& viewPort); - void (*SetScissorRect)(NonNullPtr commandList, const Rectangle& viewPort); - void (*SetBlendConstants)(NonNullPtr commandList, FColor blendConstants); - void (*SetStencilReference)(NonNullPtr commandList, uint8 reference); - void (*SetIndexBuffer)(NonNullPtr commandList, NonNullPtr buffer, - IndexFormat format, size_t indexCount, index_t offset); + void (*SetViewPort)(NonNullPtr commandList, const GraphicsViewPort& viewPort); + void (*SetScissorRect)(NonNullPtr commandList, const struct Rectangle& viewPort); + void (*SetBlendConstants)(NonNullPtr commandList, FColor blendConstants); + void (*SetStencilReference)(NonNullPtr commandList, uint8 reference); + void (*SetIndexBuffer)(NonNullPtr commandList, NonNullPtr buffer, + IndexFormat format, size_t indexCount, index_t offset); - void (*BindGraphicsPipeline)(NonNullPtr commandList, NonNullPtr graphicsPipeline); - void (*DrawPrimitives)(NonNullPtr commandList, uint32 numVertices, uint32 numInstances, - uint32 firstVertex, uint32 firstInstance); - void (*DrawIndexedPrimitives)(NonNullPtr commandList, uint32 numIndices, uint32 numInstances, - uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance); + void (*BindGraphicsPipeline)(NonNullPtr commandList, NonNullPtr graphicsPipeline); + void (*DrawPrimitives)(NonNullPtr commandList, uint32 numVertices, uint32 numInstances, + uint32 firstVertex, uint32 firstInstance); + void (*DrawIndexedPrimitives)(NonNullPtr commandList, uint32 numIndices, uint32 numInstances, + uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance); - void (*SetPushConstants)(NonNullPtr commandList, ShaderStage stage, uint32 rootParameterIndex, - uint32 numConstants, const void* constants); + void (*SetPushConstants)(NonNullPtr commandList, ShaderStage stage, uint32 rootParameterIndex, + uint32 numConstants, const void* constants); - // Fences - bool (*WaitUntilGPUIsIdle)(NonNullPtr driver); - bool (*QueryFence)(NonNullPtr driver, NonNullPtr fence); - void (*ReleaseFence)(NonNullPtr driver, NonNullPtr fence JULIET_DEBUG_PARAM(String querier)); + // Fences + bool (*WaitUntilGPUIsIdle)(NonNullPtr driver); + bool (*QueryFence)(NonNullPtr driver, NonNullPtr fence); + void (*ReleaseFence)(NonNullPtr driver, NonNullPtr fence JULIET_DEBUG_PARAM(String querier)); - // Shaders - Shader* (*CreateShader)(NonNullPtr driver, ByteBuffer shaderByteCode, - ShaderCreateInfo& shaderCreateInfo JULIET_DEBUG_PARAM(String filename)); - void (*DestroyShader)(NonNullPtr driver, NonNullPtr shader); + // Shaders + Shader* (*CreateShader)(NonNullPtr driver, ByteBuffer shaderByteCode, + ShaderCreateInfo& shaderCreateInfo JULIET_DEBUG_PARAM(String filename)); + void (*DestroyShader)(NonNullPtr driver, NonNullPtr shader); - // Pipeline - GraphicsPipeline* (*CreateGraphicsPipeline)(NonNullPtr driver, const GraphicsPipelineCreateInfo& createInfo); - void (*DestroyGraphicsPipeline)(NonNullPtr driver, NonNullPtr pipeline); - bool (*UpdateGraphicsPipelineShaders)(NonNullPtr driver, NonNullPtr graphicsPipeline, - Shader* optional_vertexShader, Shader* optional_fragmentShader); + // Pipeline + GraphicsPipeline* (*CreateGraphicsPipeline)(NonNullPtr driver, const GraphicsPipelineCreateInfo& createInfo); + void (*DestroyGraphicsPipeline)(NonNullPtr driver, NonNullPtr pipeline); + bool (*UpdateGraphicsPipelineShaders)(NonNullPtr driver, NonNullPtr graphicsPipeline, + Shader* optional_vertexShader, Shader* optional_fragmentShader); - // Textures - Texture* (*CreateTexture)(NonNullPtr driver, const TextureCreateInfo& createInfo); - void (*DestroyTexture)(NonNullPtr driver, NonNullPtr texture); + // Textures + Texture* (*CreateTexture)(NonNullPtr driver, const TextureCreateInfo& createInfo); + void (*DestroyTexture)(NonNullPtr driver, NonNullPtr texture); - // Buffers - GraphicsBuffer* (*CreateGraphicsBuffer)(NonNullPtr driver, size_t size, size_t stride, - BufferUsage usage, bool isDynamic); - void (*DestroyGraphicsBuffer)(NonNullPtr buffer); + // Buffers + GraphicsBuffer* (*CreateGraphicsBuffer)(NonNullPtr driver, size_t size, size_t stride, + BufferUsage usage, bool isDynamic); + void (*DestroyGraphicsBuffer)(NonNullPtr buffer); - void* (*MapGraphicsBuffer)(NonNullPtr driver, NonNullPtr buffer); - void (*UnmapGraphicsBuffer)(NonNullPtr driver, NonNullPtr buffer); + void* (*MapGraphicsBuffer)(NonNullPtr driver, NonNullPtr buffer); + void (*UnmapGraphicsBuffer)(NonNullPtr driver, NonNullPtr buffer); - GraphicsTransferBuffer* (*CreateGraphicsTransferBuffer)(NonNullPtr driver, size_t size, TransferBufferUsage usage); - void (*DestroyGraphicsTransferBuffer)(NonNullPtr buffer); + GraphicsTransferBuffer* (*CreateGraphicsTransferBuffer)(NonNullPtr driver, size_t size, TransferBufferUsage usage); + void (*DestroyGraphicsTransferBuffer)(NonNullPtr buffer); - void* (*MapGraphicsTransferBuffer)(NonNullPtr driver, NonNullPtr buffer); - void (*UnmapGraphicsTransferBuffer)(NonNullPtr driver, NonNullPtr buffer); - void (*CopyBuffer)(NonNullPtr commandList, NonNullPtr dst, - NonNullPtr src, size_t size, size_t dstOffset, size_t srcOffset); - void (*CopyBufferToTexture)(NonNullPtr commandList, NonNullPtr dst, - NonNullPtr src); // Assume full copy for now + void* (*MapGraphicsTransferBuffer)(NonNullPtr driver, NonNullPtr buffer); + void (*UnmapGraphicsTransferBuffer)(NonNullPtr driver, NonNullPtr buffer); + void (*CopyBuffer)(NonNullPtr commandList, NonNullPtr dst, + NonNullPtr src, size_t size, size_t dstOffset, size_t srcOffset); + void (*CopyBufferToTexture)(NonNullPtr commandList, NonNullPtr dst, + NonNullPtr src); // Assume full copy for now - void (*TransitionBufferToReadable)(NonNullPtr commandList, NonNullPtr buffer); - uint32 (*GetDescriptorIndex)(NonNullPtr device, NonNullPtr buffer); - uint32 (*GetDescriptorIndexTexture)(NonNullPtr device, NonNullPtr texture); + void (*TransitionBufferToReadable)(NonNullPtr commandList, NonNullPtr buffer); + uint32 (*GetDescriptorIndex)(NonNullPtr device, NonNullPtr buffer); + uint32 (*GetDescriptorIndexTexture)(NonNullPtr device, NonNullPtr texture); - const char* Name = "Unknown"; - GPUDriver* Driver = nullptr; - bool DebugEnabled : 1; - }; + const char* Name = "Unknown"; + GPUDriver* Driver = nullptr; + bool DebugEnabled : 1; +}; - struct GraphicsDeviceFactory - { - const char* Name = "Unknown"; - DriverType Type = DriverType::Any; - bool (*CheckDriver)(void); - GraphicsDevice* (*CreateGraphicsDevice)(bool enableDebug); - }; +struct GraphicsDeviceFactory +{ + const char* Name = "Unknown"; + GraphicsDriverType Type = GraphicsDriverType::Any; + bool (*CheckDriver)(void); + GraphicsDevice* (*CreateGraphicsDevice)(bool enableDebug); +}; - extern GraphicsDeviceFactory DX12DeviceFactory; -} // namespace Juliet +extern GraphicsDeviceFactory DX12DeviceFactory; diff --git a/Juliet/src/Graphics/ImGuiRenderer.cpp b/Juliet/src/Graphics/ImGuiRenderer.cpp index 42c6f2e..6c18100 100644 --- a/Juliet/src/Graphics/ImGuiRenderer.cpp +++ b/Juliet/src/Graphics/ImGuiRenderer.cpp @@ -15,424 +15,421 @@ #include #include -namespace Juliet +namespace { - namespace + constexpr uint32 kMaxFramesInFlight = 2; + + struct FrameResources { - constexpr uint32 kMaxFramesInFlight = 2; + GraphicsBuffer* VertexBuffer = nullptr; + GraphicsBuffer* IndexBuffer = nullptr; + GraphicsTransferBuffer* VertexUpload = nullptr; + GraphicsTransferBuffer* IndexUpload = nullptr; + uint32 VertexBufferSize = 0; // In bytes + uint32 IndexBufferSize = 0; // In bytes + }; - struct FrameResources - { - GraphicsBuffer* VertexBuffer = nullptr; - GraphicsBuffer* IndexBuffer = nullptr; - GraphicsTransferBuffer* VertexUpload = nullptr; - GraphicsTransferBuffer* IndexUpload = nullptr; - uint32 VertexBufferSize = 0; // In bytes - uint32 IndexBufferSize = 0; // In bytes - }; - - struct ImGuiRendererState - { - GraphicsDevice* Device; - GraphicsPipeline* Pipeline; - - // Resources - Texture* FontTexture; - Shader* VertexShader; - Shader* FragmentShader; - - // Frame Data - FrameResources Frames[kMaxFramesInFlight]; - uint32 FrameIndex; - - bool Initialized; - }; - - ImGuiRendererState g_ImGuiState = {}; - - // Helper to resize buffers for a specific frame - void EnsureBufferSize(FrameResources& frame, uint32 requiredVertexBytes, uint32 requiredIndexBytes) - { - bool needVertexRealloc = requiredVertexBytes > frame.VertexBufferSize; - bool needIndexRealloc = requiredIndexBytes > frame.IndexBufferSize; - - // If any buffer needs reallocation, wait for GPU to finish using everybody to be safe. - // Ideally we only wait for this specific frame's fence, but we don't have that granularity easily exposed - // here. Resizing is rare, so global wait is acceptable. - if (needVertexRealloc || needIndexRealloc) - { - WaitUntilGPUIsIdle(g_ImGuiState.Device); - } - - if (needVertexRealloc) - { - if (frame.VertexBuffer) - { - DestroyGraphicsBuffer(g_ImGuiState.Device, frame.VertexBuffer); - } - if (frame.VertexUpload) - { - DestroyGraphicsTransferBuffer(g_ImGuiState.Device, frame.VertexUpload); - } - - frame.VertexBufferSize = requiredVertexBytes + 5000 * sizeof(ImDrawVert); // Growth factor - - BufferCreateInfo vci = {}; - vci.Size = frame.VertexBufferSize; - vci.Usage = BufferUsage::StructuredBuffer; - frame.VertexBuffer = CreateGraphicsBuffer(g_ImGuiState.Device, vci); - - TransferBufferCreateInfo tvci = {}; - tvci.Size = frame.VertexBufferSize; - tvci.Usage = TransferBufferUsage::Upload; - frame.VertexUpload = CreateGraphicsTransferBuffer(g_ImGuiState.Device, tvci); - } - - if (needIndexRealloc) - { - if (frame.IndexBuffer) - { - DestroyGraphicsBuffer(g_ImGuiState.Device, frame.IndexBuffer); - } - if (frame.IndexUpload) - { - DestroyGraphicsTransferBuffer(g_ImGuiState.Device, frame.IndexUpload); - } - - frame.IndexBufferSize = requiredIndexBytes + 10000 * sizeof(ImDrawIdx); - - BufferCreateInfo ici = {}; - ici.Size = frame.IndexBufferSize; - ici.Usage = BufferUsage::IndexBuffer; - frame.IndexBuffer = CreateGraphicsBuffer(g_ImGuiState.Device, ici); - - TransferBufferCreateInfo tici = {}; - tici.Size = frame.IndexBufferSize; - tici.Usage = TransferBufferUsage::Upload; - frame.IndexUpload = CreateGraphicsTransferBuffer(g_ImGuiState.Device, tici); - } - } - - } // namespace - - bool ImGuiRenderer_Initialize(GraphicsDevice* device) + struct ImGuiRendererState { - printf("ImGuiRenderer_Initialize: device=%p, g_ImGuiState=%p, Initialized=%d\n", (void*)device, - (void*)&g_ImGuiState, g_ImGuiState.Initialized); - if (g_ImGuiState.Initialized) - { - return true; - } + GraphicsDevice* Device; + GraphicsPipeline* Pipeline; - g_ImGuiState.Device = device; + // Resources + Texture* FontTexture; + Shader* VertexShader; + Shader* FragmentShader; - // Load Shaders - String entryPoint = WrapString("main"); - ShaderCreateInfo shaderCI = {}; - shaderCI.EntryPoint = entryPoint; + // Frame Data + FrameResources Frames[kMaxFramesInFlight]; + uint32 FrameIndex; - TempArena path = scratch_begin(0, 0); + bool Initialized; + }; - String vertPath = GetAssetPath(path.Arena, WrapString("ImGui.vert.dxil")); - shaderCI.Stage = ShaderStage::Vertex; - g_ImGuiState.VertexShader = CreateShader(device, vertPath, shaderCI); + ImGuiRendererState g_ImGuiState = {}; - String fragPath = GetAssetPath(path.Arena, WrapString("ImGui.frag.dxil")); - shaderCI.Stage = ShaderStage::Fragment; - g_ImGuiState.FragmentShader = CreateShader(device, fragPath, shaderCI); - - scratch_end(path); - - if (!g_ImGuiState.VertexShader || !g_ImGuiState.FragmentShader) - { - LogError(LogCategory::Graphics, "Failed to load ImGui shaders"); - return false; - } - - // Build Font Texture - ImGuiIO& io = ImGui::GetIO(); - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); - - TextureCreateInfo texCI = {}; - texCI.Type = TextureType::Texture_2D; - texCI.Width = static_cast(width); - texCI.Height = static_cast(height); - - texCI.Format = TextureFormat::R8G8B8A8_UNORM; - texCI.Flags = TextureUsageFlag::Sampler; - texCI.LayerCount = 1; - texCI.MipLevelCount = 1; - texCI.SampleCount = TextureSampleCount::One; - - g_ImGuiState.FontTexture = CreateTexture(device, texCI); - io.Fonts->SetTexID(reinterpret_cast(g_ImGuiState.FontTexture)); - - // Upload data - uint32 rowPitch = static_cast(width) * 4u; - uint32 alignedRowPitch = (rowPitch + 255u) & ~255u; - uint32 textureSize = alignedRowPitch * static_cast(height); - - TransferBufferCreateInfo tbci = {}; - tbci.Size = textureSize; - tbci.Usage = TransferBufferUsage::Upload; - GraphicsTransferBuffer* tb = CreateGraphicsTransferBuffer(device, tbci); - if (!tb) - { - Log(LogLevel::Error, LogCategory::Graphics, "ImGuiRenderer: Failed to create font upload buffer"); - return false; - } - - auto* dst = static_cast(MapGraphicsTransferBuffer(device, tb)); - - for (uint32 y = 0; y < static_cast(height); ++y) - { - MemCopy(dst + y * alignedRowPitch, pixels + y * rowPitch, rowPitch); - } - - UnmapGraphicsTransferBuffer(device, tb); - - CommandList* cmd = AcquireCommandList(device); - CopyBufferToTexture(cmd, g_ImGuiState.FontTexture, tb); - - SubmitCommandLists(cmd); - - WaitUntilGPUIsIdle(device); - - DestroyGraphicsTransferBuffer(device, tb); - - // Init Frame Data - g_ImGuiState.FrameIndex = 0; - for (uint32 i = 0; i < kMaxFramesInFlight; ++i) - { - g_ImGuiState.Frames[i] = {}; - } - - g_ImGuiState.Initialized = true; - return true; - } - - void ImGuiRenderer_Shutdown(GraphicsDevice* device) + // Helper to resize buffers for a specific frame + void EnsureBufferSize(FrameResources& frame, uint32 requiredVertexBytes, uint32 requiredIndexBytes) { - if (!g_ImGuiState.Initialized) + bool needVertexRealloc = requiredVertexBytes > frame.VertexBufferSize; + bool needIndexRealloc = requiredIndexBytes > frame.IndexBufferSize; + + // If any buffer needs reallocation, wait for GPU to finish using everybody to be safe. + // Ideally we only wait for this specific frame's fence, but we don't have that granularity easily exposed + // here. Resizing is rare, so global wait is acceptable. + if (needVertexRealloc || needIndexRealloc) { - return; + WaitUntilGPUIsIdle(g_ImGuiState.Device); } - WaitUntilGPUIsIdle(device); - - if (g_ImGuiState.Pipeline) + if (needVertexRealloc) { - DestroyGraphicsPipeline(device, g_ImGuiState.Pipeline); - } - if (g_ImGuiState.VertexShader) - { - DestroyShader(device, g_ImGuiState.VertexShader); - } - if (g_ImGuiState.FragmentShader) - { - DestroyShader(device, g_ImGuiState.FragmentShader); - } - if (g_ImGuiState.FontTexture) - { - DestroyTexture(device, g_ImGuiState.FontTexture); - } - - for (uint32 i = 0; i < kMaxFramesInFlight; ++i) - { - FrameResources& frame = g_ImGuiState.Frames[i]; if (frame.VertexBuffer) { - DestroyGraphicsBuffer(device, frame.VertexBuffer); - } - if (frame.IndexBuffer) - { - DestroyGraphicsBuffer(device, frame.IndexBuffer); + DestroyGraphicsBuffer(g_ImGuiState.Device, frame.VertexBuffer); } if (frame.VertexUpload) { - DestroyGraphicsTransferBuffer(device, frame.VertexUpload); + DestroyGraphicsTransferBuffer(g_ImGuiState.Device, frame.VertexUpload); + } + + frame.VertexBufferSize = requiredVertexBytes + 5000 * sizeof(ImDrawVert); // Growth factor + + BufferCreateInfo vci = {}; + vci.Size = frame.VertexBufferSize; + vci.Usage = BufferUsage::StructuredBuffer; + frame.VertexBuffer = CreateGraphicsBuffer(g_ImGuiState.Device, vci); + + TransferBufferCreateInfo tvci = {}; + tvci.Size = frame.VertexBufferSize; + tvci.Usage = TransferBufferUsage::Upload; + frame.VertexUpload = CreateGraphicsTransferBuffer(g_ImGuiState.Device, tvci); + } + + if (needIndexRealloc) + { + if (frame.IndexBuffer) + { + DestroyGraphicsBuffer(g_ImGuiState.Device, frame.IndexBuffer); } if (frame.IndexUpload) { - DestroyGraphicsTransferBuffer(device, frame.IndexUpload); + DestroyGraphicsTransferBuffer(g_ImGuiState.Device, frame.IndexUpload); } - frame = {}; - } - g_ImGuiState = {}; + frame.IndexBufferSize = requiredIndexBytes + 10000 * sizeof(ImDrawIdx); + + BufferCreateInfo ici = {}; + ici.Size = frame.IndexBufferSize; + ici.Usage = BufferUsage::IndexBuffer; + frame.IndexBuffer = CreateGraphicsBuffer(g_ImGuiState.Device, ici); + + TransferBufferCreateInfo tici = {}; + tici.Size = frame.IndexBufferSize; + tici.Usage = TransferBufferUsage::Upload; + frame.IndexUpload = CreateGraphicsTransferBuffer(g_ImGuiState.Device, tici); + } } - void ImGuiRenderer_NewFrame() +} // namespace + +bool ImGuiRenderer_Initialize(GraphicsDevice* device) +{ + printf("ImGuiRenderer_Initialize: device=%p, g_ImGuiState=%p, Initialized=%d\n", (void*)device, + (void*)&g_ImGuiState, g_ImGuiState.Initialized); + if (g_ImGuiState.Initialized) { - ImGui_ImplWin32_NewFrame(); // Assumes Win32 initialized elsewhere - ImGui::NewFrame(); + return true; } - void ImGuiRenderer_Render(CommandList* cmdList, RenderPass* renderPass) + g_ImGuiState.Device = device; + + // Load Shaders + String entryPoint = WrapString("main"); + ShaderCreateInfo shaderCI = {}; + shaderCI.EntryPoint = entryPoint; + + TempArena path = scratch_begin(0, 0); + + String vertPath = GetAssetPath(path.Arena, WrapString("ImGui.vert.dxil")); + shaderCI.Stage = ShaderStage::Vertex; + g_ImGuiState.VertexShader = CreateShader(device, vertPath, shaderCI); + + String fragPath = GetAssetPath(path.Arena, WrapString("ImGui.frag.dxil")); + shaderCI.Stage = ShaderStage::Fragment; + g_ImGuiState.FragmentShader = CreateShader(device, fragPath, shaderCI); + + scratch_end(path); + + if (!g_ImGuiState.VertexShader || !g_ImGuiState.FragmentShader) { - if (!g_ImGuiState.Initialized) + LogError(LogCategory::Graphics, "Failed to load ImGui shaders"); + return false; + } + + // Build Font Texture + ImGuiIO& io = ImGui::GetIO(); + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + + TextureCreateInfo texCI = {}; + texCI.Type = TextureType::Texture_2D; + texCI.Width = static_cast(width); + texCI.Height = static_cast(height); + + texCI.Format = TextureFormat::R8G8B8A8_UNORM; + texCI.Flags = TextureUsageFlag::Sampler; + texCI.LayerCount = 1; + texCI.MipLevelCount = 1; + texCI.SampleCount = TextureSampleCount::One; + + g_ImGuiState.FontTexture = CreateTexture(device, texCI); + io.Fonts->SetTexID(reinterpret_cast(g_ImGuiState.FontTexture)); + + // Upload data + uint32 rowPitch = static_cast(width) * 4u; + uint32 alignedRowPitch = (rowPitch + 255u) & ~255u; + uint32 textureSize = alignedRowPitch * static_cast(height); + + TransferBufferCreateInfo tbci = {}; + tbci.Size = textureSize; + tbci.Usage = TransferBufferUsage::Upload; + GraphicsTransferBuffer* tb = CreateGraphicsTransferBuffer(device, tbci); + if (!tb) + { + Log(LogLevel::Error, LogCategory::Graphics, "ImGuiRenderer: Failed to create font upload buffer"); + return false; + } + + auto* dst = static_cast(MapGraphicsTransferBuffer(device, tb)); + + for (uint32 y = 0; y < static_cast(height); ++y) + { + MemCopy(dst + y * alignedRowPitch, pixels + y * rowPitch, rowPitch); + } + + UnmapGraphicsTransferBuffer(device, tb); + + CommandList* cmd = AcquireCommandList(device); + CopyBufferToTexture(cmd, g_ImGuiState.FontTexture, tb); + + SubmitCommandLists(cmd); + + WaitUntilGPUIsIdle(device); + + DestroyGraphicsTransferBuffer(device, tb); + + // Init Frame Data + g_ImGuiState.FrameIndex = 0; + for (uint32 i = 0; i < kMaxFramesInFlight; ++i) + { + g_ImGuiState.Frames[i] = {}; + } + + g_ImGuiState.Initialized = true; + return true; +} + +void ImGuiRenderer_Shutdown(GraphicsDevice* device) +{ + if (!g_ImGuiState.Initialized) + { + return; + } + + WaitUntilGPUIsIdle(device); + + if (g_ImGuiState.Pipeline) + { + DestroyGraphicsPipeline(device, g_ImGuiState.Pipeline); + } + if (g_ImGuiState.VertexShader) + { + DestroyShader(device, g_ImGuiState.VertexShader); + } + if (g_ImGuiState.FragmentShader) + { + DestroyShader(device, g_ImGuiState.FragmentShader); + } + if (g_ImGuiState.FontTexture) + { + DestroyTexture(device, g_ImGuiState.FontTexture); + } + + for (uint32 i = 0; i < kMaxFramesInFlight; ++i) + { + FrameResources& frame = g_ImGuiState.Frames[i]; + if (frame.VertexBuffer) { - return; + DestroyGraphicsBuffer(device, frame.VertexBuffer); } - - ImGui::Render(); - ImDrawData* drawData = ImGui::GetDrawData(); - - if (!drawData || drawData->CmdListsCount == 0) + if (frame.IndexBuffer) { - return; + DestroyGraphicsBuffer(device, frame.IndexBuffer); } - - // Lazy create pipeline - if (!g_ImGuiState.Pipeline) + if (frame.VertexUpload) { - // Assume B8G8R8A8_UNORM for SwapChain - GraphicsPipelineCreateInfo pci = {}; - pci.VertexShader = g_ImGuiState.VertexShader; - pci.FragmentShader = g_ImGuiState.FragmentShader; - pci.PrimitiveType = PrimitiveType::TriangleList; - pci.RasterizerState.FillMode = FillMode::Solid; - pci.RasterizerState.CullMode = CullMode::None; - - ColorTargetDescription colorDesc = {}; - colorDesc.Format = TextureFormat::B8G8R8A8_UNORM; // Match SwapChain - - // Blend State - colorDesc.BlendState.EnableBlend = true; - colorDesc.BlendState.SourceColorBlendFactor = BlendFactor::Src_Alpha; - colorDesc.BlendState.DestinationColorBlendFactor = BlendFactor::One_Minus_Src_Alpha; - colorDesc.BlendState.ColorBlendOperation = BlendOperation::Add; - colorDesc.BlendState.SourceAlphaBlendFactor = BlendFactor::One; - colorDesc.BlendState.DestinationAlphaBlendFactor = BlendFactor::One_Minus_Src_Alpha; - colorDesc.BlendState.AlphaBlendOperation = BlendOperation::Add; - colorDesc.BlendState.EnableColorWriteMask = true; - colorDesc.BlendState.ColorWriteMask = - ColorComponentFlags::R | ColorComponentFlags::G | ColorComponentFlags::B | ColorComponentFlags::A; - - pci.TargetInfo.ColorTargetDescriptions = &colorDesc; - pci.TargetInfo.NumColorTargets = 1; - - g_ImGuiState.Pipeline = CreateGraphicsPipeline(g_ImGuiState.Device, pci); + DestroyGraphicsTransferBuffer(device, frame.VertexUpload); } - - // Cycle Frame - g_ImGuiState.FrameIndex = (g_ImGuiState.FrameIndex + 1) % kMaxFramesInFlight; - FrameResources& currentFrame = g_ImGuiState.Frames[g_ImGuiState.FrameIndex]; - - // Upload Buffers - uint32 totalVtx = static_cast(drawData->TotalVtxCount); - uint32 totalIdx = static_cast(drawData->TotalIdxCount); - - EnsureBufferSize(currentFrame, totalVtx * sizeof(ImDrawVert), totalIdx * sizeof(ImDrawIdx)); - - auto* vtxDst = static_cast(MapGraphicsTransferBuffer(g_ImGuiState.Device, currentFrame.VertexUpload)); - auto* idxDst = static_cast(MapGraphicsTransferBuffer(g_ImGuiState.Device, currentFrame.IndexUpload)); - - for (int n = 0; n < drawData->CmdListsCount; n++) + if (frame.IndexUpload) { - const ImDrawList* cmd_list = drawData->CmdLists[n]; - MemCopy(vtxDst, cmd_list->VtxBuffer.Data, static_cast(cmd_list->VtxBuffer.Size) * sizeof(ImDrawVert)); - MemCopy(idxDst, cmd_list->IdxBuffer.Data, static_cast(cmd_list->IdxBuffer.Size) * sizeof(ImDrawIdx)); - vtxDst += cmd_list->VtxBuffer.Size; - idxDst += cmd_list->IdxBuffer.Size; + DestroyGraphicsTransferBuffer(device, frame.IndexUpload); } + frame = {}; + } - UnmapGraphicsTransferBuffer(g_ImGuiState.Device, currentFrame.VertexUpload); - UnmapGraphicsTransferBuffer(g_ImGuiState.Device, currentFrame.IndexUpload); + g_ImGuiState = {}; +} - // Copy both vertex and index buffers to GPU - CopyBuffer(cmdList, currentFrame.VertexBuffer, currentFrame.VertexUpload, totalVtx * sizeof(ImDrawVert)); - CopyBuffer(cmdList, currentFrame.IndexBuffer, currentFrame.IndexUpload, totalIdx * sizeof(ImDrawIdx)); +void ImGuiRenderer_NewFrame() +{ + ImGui_ImplWin32_NewFrame(); // Assumes Win32 initialized elsewhere + ImGui::NewFrame(); +} - // Transition vertex buffer to SRV state (this barrier waits for copy to complete) - TransitionBufferToReadable(cmdList, currentFrame.VertexBuffer); +void ImGuiRenderer_Render(CommandList* cmdList, RenderPass* renderPass) +{ + if (!g_ImGuiState.Initialized) + { + return; + } - // SetIndexBuffer transitions from COPY_DEST to INDEX_BUFFER (barrier waits for copy to complete) - SetIndexBuffer(cmdList, currentFrame.IndexBuffer, IndexFormat::UInt16, totalIdx, 0); + ImGui::Render(); + ImDrawData* drawData = ImGui::GetDrawData(); - // Render - BindGraphicsPipeline(renderPass, g_ImGuiState.Pipeline); + if (!drawData || drawData->CmdListsCount == 0) + { + return; + } - // Setup Viewport / Scale - float L = drawData->DisplayPos.x; - float R = drawData->DisplayPos.x + drawData->DisplaySize.x; - float T = drawData->DisplayPos.y; - float B = drawData->DisplayPos.y + drawData->DisplaySize.y; + // Lazy create pipeline + if (!g_ImGuiState.Pipeline) + { + // Assume B8G8R8A8_UNORM for SwapChain + GraphicsPipelineCreateInfo pci = {}; + pci.VertexShader = g_ImGuiState.VertexShader; + pci.FragmentShader = g_ImGuiState.FragmentShader; + pci.PrimitiveType = PrimitiveType::TriangleList; + pci.RasterizerState.FillMode = FillMode::Solid; + pci.RasterizerState.CullMode = CullMode::None; - float scale[2]; - scale[0] = 2.0f / (R - L); - scale[1] = -2.0f / (B - T); + ColorTargetDescription colorDesc = {}; + colorDesc.Format = TextureFormat::B8G8R8A8_UNORM; // Match SwapChain - float translate[2]; - translate[0] = -1.0f - L * scale[0]; - translate[1] = 1.0f - T * scale[1]; + // Blend State + colorDesc.BlendState.EnableBlend = true; + colorDesc.BlendState.SourceColorBlendFactor = BlendFactor::Src_Alpha; + colorDesc.BlendState.DestinationColorBlendFactor = BlendFactor::One_Minus_Src_Alpha; + colorDesc.BlendState.ColorBlendOperation = BlendOperation::Add; + colorDesc.BlendState.SourceAlphaBlendFactor = BlendFactor::One; + colorDesc.BlendState.DestinationAlphaBlendFactor = BlendFactor::One_Minus_Src_Alpha; + colorDesc.BlendState.AlphaBlendOperation = BlendOperation::Add; + colorDesc.BlendState.EnableColorWriteMask = true; + colorDesc.BlendState.ColorWriteMask = + ColorComponentFlags::R | ColorComponentFlags::G | ColorComponentFlags::B | ColorComponentFlags::A; - // Global State (Display Size, etc) + pci.TargetInfo.ColorTargetDescriptions = &colorDesc; + pci.TargetInfo.NumColorTargets = 1; - uint32 globalVtxOffset = 0; - uint32 globalIdxOffset = 0; + g_ImGuiState.Pipeline = CreateGraphicsPipeline(g_ImGuiState.Device, pci); + } - ImVec2 clip_off = drawData->DisplayPos; - ImVec2 clip_scale = drawData->FramebufferScale; + // Cycle Frame + g_ImGuiState.FrameIndex = (g_ImGuiState.FrameIndex + 1) % kMaxFramesInFlight; + FrameResources& currentFrame = g_ImGuiState.Frames[g_ImGuiState.FrameIndex]; - for (int n = 0; n < drawData->CmdListsCount; n++) + // Upload Buffers + uint32 totalVtx = static_cast(drawData->TotalVtxCount); + uint32 totalIdx = static_cast(drawData->TotalIdxCount); + + EnsureBufferSize(currentFrame, totalVtx * sizeof(ImDrawVert), totalIdx * sizeof(ImDrawIdx)); + + auto* vtxDst = static_cast(MapGraphicsTransferBuffer(g_ImGuiState.Device, currentFrame.VertexUpload)); + auto* idxDst = static_cast(MapGraphicsTransferBuffer(g_ImGuiState.Device, currentFrame.IndexUpload)); + + for (int n = 0; n < drawData->CmdListsCount; n++) + { + const ImDrawList* cmd_list = drawData->CmdLists[n]; + MemCopy(vtxDst, cmd_list->VtxBuffer.Data, static_cast(cmd_list->VtxBuffer.Size) * sizeof(ImDrawVert)); + MemCopy(idxDst, cmd_list->IdxBuffer.Data, static_cast(cmd_list->IdxBuffer.Size) * sizeof(ImDrawIdx)); + vtxDst += cmd_list->VtxBuffer.Size; + idxDst += cmd_list->IdxBuffer.Size; + } + + UnmapGraphicsTransferBuffer(g_ImGuiState.Device, currentFrame.VertexUpload); + UnmapGraphicsTransferBuffer(g_ImGuiState.Device, currentFrame.IndexUpload); + + // Copy both vertex and index buffers to GPU + CopyBuffer(cmdList, currentFrame.VertexBuffer, currentFrame.VertexUpload, totalVtx * sizeof(ImDrawVert)); + CopyBuffer(cmdList, currentFrame.IndexBuffer, currentFrame.IndexUpload, totalIdx * sizeof(ImDrawIdx)); + + // Transition vertex buffer to SRV state (this barrier waits for copy to complete) + TransitionBufferToReadable(cmdList, currentFrame.VertexBuffer); + + // SetIndexBuffer transitions from COPY_DEST to INDEX_BUFFER (barrier waits for copy to complete) + SetIndexBuffer(cmdList, currentFrame.IndexBuffer, IndexFormat::UInt16, totalIdx, 0); + + // Render + BindGraphicsPipeline(renderPass, g_ImGuiState.Pipeline); + + // Setup Viewport / Scale + float L = drawData->DisplayPos.x; + float R = drawData->DisplayPos.x + drawData->DisplaySize.x; + float T = drawData->DisplayPos.y; + float B = drawData->DisplayPos.y + drawData->DisplaySize.y; + + float scale[2]; + scale[0] = 2.0f / (R - L); + scale[1] = -2.0f / (B - T); + + float translate[2]; + translate[0] = -1.0f - L * scale[0]; + translate[1] = 1.0f - T * scale[1]; + + // Global State (Display Size, etc) + + uint32 globalVtxOffset = 0; + uint32 globalIdxOffset = 0; + + ImVec2 clip_off = drawData->DisplayPos; + ImVec2 clip_scale = drawData->FramebufferScale; + + for (int n = 0; n < drawData->CmdListsCount; n++) + { + const ImDrawList* cmd_list = drawData->CmdLists[n]; + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { - const ImDrawList* cmd_list = drawData->CmdLists[n]; - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback != nullptr) { - const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback != nullptr) + pcmd->UserCallback(cmd_list, pcmd); + } + else + { + // Project scissor/clipping rectangles into framebuffer space + ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, + (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); + ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, + (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); + + // Skip draw commands with zero-sized scissor rectangles + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) { - pcmd->UserCallback(cmd_list, pcmd); + continue; } - else - { - // Project scissor/clipping rectangles into framebuffer space - ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, - (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); - ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, - (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); - // Skip draw commands with zero-sized scissor rectangles - if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) - { - continue; - } + // Set scissor rect (clipping rectangle) + struct Rectangle scissorRect = {}; + scissorRect.X = static_cast(clip_min.x); + scissorRect.Y = static_cast(clip_min.y); + scissorRect.Width = static_cast(clip_max.x - clip_min.x); + scissorRect.Height = static_cast(clip_max.y - clip_min.y); + SetScissorRect(renderPass, scissorRect); - // Set scissor rect (clipping rectangle) - Rectangle scissorRect = {}; - scissorRect.X = static_cast(clip_min.x); - scissorRect.Y = static_cast(clip_min.y); - scissorRect.Width = static_cast(clip_max.x - clip_min.x); - scissorRect.Height = static_cast(clip_max.y - clip_min.y); - SetScissorRect(renderPass, scissorRect); + // Bind Texture + uint32 textureIndex = GetDescriptorIndex(g_ImGuiState.Device, reinterpret_cast(pcmd->GetTexID())); - // Bind Texture - uint32 textureIndex = GetDescriptorIndex(g_ImGuiState.Device, reinterpret_cast(pcmd->GetTexID())); + // Push Constants + PushData pushData = {}; // Zero-initialize all fields - // Push Constants - PushData pushData = {}; // Zero-initialize all fields + pushData.BufferIndex = GetDescriptorIndex(g_ImGuiState.Device, currentFrame.VertexBuffer); + pushData.TextureIndex = textureIndex; + pushData.VertexOffset = pcmd->VtxOffset + globalVtxOffset; // Pass vertex offset for bindless + pushData.Scale[0] = scale[0]; + pushData.Scale[1] = scale[1]; + pushData.Translate[0] = translate[0]; + pushData.Translate[1] = translate[1]; - pushData.BufferIndex = GetDescriptorIndex(g_ImGuiState.Device, currentFrame.VertexBuffer); - pushData.TextureIndex = textureIndex; - pushData.VertexOffset = pcmd->VtxOffset + globalVtxOffset; // Pass vertex offset for bindless - pushData.Scale[0] = scale[0]; - pushData.Scale[1] = scale[1]; - pushData.Translate[0] = translate[0]; - pushData.Translate[1] = translate[1]; + SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData); - SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData); - - // Draw - pass 0 for vertexOffset since shader handles it via push constants - DrawIndexedPrimitives(renderPass, pcmd->ElemCount, 1, pcmd->IdxOffset + globalIdxOffset, 0, 0); - } + // Draw - pass 0 for vertexOffset since shader handles it via push constants + DrawIndexedPrimitives(renderPass, pcmd->ElemCount, 1, pcmd->IdxOffset + globalIdxOffset, 0, 0); } - globalIdxOffset += static_cast(cmd_list->IdxBuffer.Size); - globalVtxOffset += static_cast(cmd_list->VtxBuffer.Size); } + globalIdxOffset += static_cast(cmd_list->IdxBuffer.Size); + globalVtxOffset += static_cast(cmd_list->VtxBuffer.Size); } -} // namespace Juliet +} #endif // JULIET_ENABLE_IMGUI diff --git a/Juliet/src/Graphics/Mesh.cpp b/Juliet/src/Graphics/Mesh.cpp index e399355..2988f46 100644 --- a/Juliet/src/Graphics/Mesh.cpp +++ b/Juliet/src/Graphics/Mesh.cpp @@ -1,9 +1,6 @@ -#include +#include #include #include -namespace Juliet -{ -} // namespace Juliet diff --git a/Juliet/src/Graphics/MeshRenderer.cpp b/Juliet/src/Graphics/MeshRenderer.cpp index 39336ca..e4ed512 100644 --- a/Juliet/src/Graphics/MeshRenderer.cpp +++ b/Juliet/src/Graphics/MeshRenderer.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -10,569 +10,566 @@ #include #include -namespace Juliet +namespace { - namespace + struct MeshRendererState { - struct MeshRendererState - { - GraphicsDevice* Device = nullptr; - GraphicsPipeline* Pipeline = nullptr; - GraphicsBuffer* VertexBuffer = nullptr; - GraphicsBuffer* IndexBuffer = nullptr; - GraphicsBuffer* LightsBuffer = nullptr; - GraphicsBuffer* TransformsBuffer = nullptr; - GraphicsTransferBuffer* LoadCopyBuffer = nullptr; + GraphicsDevice* Device = nullptr; + GraphicsPipeline* Pipeline = nullptr; + GraphicsBuffer* VertexBuffer = nullptr; + GraphicsBuffer* IndexBuffer = nullptr; + GraphicsBuffer* LightsBuffer = nullptr; + GraphicsBuffer* TransformsBuffer = nullptr; + GraphicsTransferBuffer* LoadCopyBuffer = nullptr; - VectorArena MeshAssets; - VectorArena MaterialAssets; - VectorArena MeshInstances; + VectorArena MeshAssets; + VectorArena MaterialAssets; + VectorArena MeshInstances; - VectorArena Vertices; - VectorArena Indices; - VectorArena PointLights; + VectorArena Vertices; + VectorArena Indices; + VectorArena PointLights; - PointLight* MappedLights = nullptr; - Matrix* MappedTransforms = nullptr; + PointLight* MappedLights = nullptr; + Matrix* MappedTransforms = nullptr; - Vector3 GlobalLightDirection = { 0.0f, -1.0f, 0.0f }; - Vector3 GlobalLightColor = { 0.0f, 0.0f, 0.0f }; - float GlobalAmbientIntensity = 0.0f; - }; + Vector3 GlobalLightDirection = { 0.0f, -1.0f, 0.0f }; + Vector3 GlobalLightColor = { 0.0f, 0.0f, 0.0f }; + float GlobalAmbientIntensity = 0.0f; + }; - MeshRendererState g_MeshRenderer; + MeshRendererState g_MeshRenderer; - MeshAssetID CubePrimitiveMeshAssetID = static_cast(-1); - MeshAssetID QuadPrimitiveMeshAssetID = static_cast(-1); - MeshAssetID SpherePrimitiveMeshAssetID = static_cast(-1); - } // namespace + MeshAssetID CubePrimitiveMeshAssetID = static_cast(-1); + MeshAssetID QuadPrimitiveMeshAssetID = static_cast(-1); + MeshAssetID SpherePrimitiveMeshAssetID = static_cast(-1); +} // namespace - MeshAssetID CreateCubePrimitive(); - MeshAssetID CreateQuadPrimitive(); - MeshAssetID CreateSpherePrimitive(); +MeshAssetID CreateCubePrimitive(); +MeshAssetID CreateQuadPrimitive(); +MeshAssetID CreateSpherePrimitive(); - void InitializeMeshRenderer(NonNullPtr assetArena, NonNullPtr instanceArena) +void InitializeMeshRenderer(NonNullPtr assetArena, NonNullPtr instanceArena) +{ + g_MeshRenderer.MeshAssets.Create(assetArena JULIET_DEBUG_PARAM("MeshAssets")); + g_MeshRenderer.MaterialAssets.Create(assetArena JULIET_DEBUG_PARAM("MaterialAssets")); + g_MeshRenderer.MeshInstances.Create(instanceArena JULIET_DEBUG_PARAM("MeshInstances")); + g_MeshRenderer.Vertices.Create(assetArena JULIET_DEBUG_PARAM("Vertices")); + g_MeshRenderer.Indices.Create(assetArena JULIET_DEBUG_PARAM("Indices")); + g_MeshRenderer.PointLights.Create(instanceArena JULIET_DEBUG_PARAM("PointLights")); + + // Create primitives + CubePrimitiveMeshAssetID = CreateCubePrimitive(); + QuadPrimitiveMeshAssetID = CreateQuadPrimitive(); + // SpherePrimitiveMeshAssetID = CreateSpherePrimitive(); // Will implement later + + // Create default material asset (ID = 0) + MaterialAsset defaultMaterial = {}; + g_MeshRenderer.MaterialAssets.PushBack(defaultMaterial); +} + +bool InitializeMeshRendererGraphics(NonNullPtr device, NonNullPtr window) +{ + bool result = true; + + GraphicsDevice* graphicsDevice = g_MeshRenderer.Device = device.Get(); + + // Create graphics pipeline + String entryPoint = WrapString("main"); + ShaderCreateInfo shaderCI = {}; + shaderCI.EntryPoint = entryPoint; + + TempArena path = scratch_begin(0, 0); + + String shaderPath = GetAssetPath(path.Arena, WrapString("Triangle.vert.dxil")); + shaderCI.Stage = ShaderStage::Vertex; + Shader* vertexShader = CreateShader(graphicsDevice, shaderPath, shaderCI); + + shaderPath = GetAssetPath(path.Arena, WrapString("SolidColor.frag.dxil")); + shaderCI.Stage = ShaderStage::Fragment; + Shader* fragmentShader = CreateShader(graphicsDevice, shaderPath, shaderCI); + + scratch_end(path); + + ColorTargetDescription colorTargetDescription = {}; + colorTargetDescription.Format = GetSwapChainTextureFormat(graphicsDevice, window); + + GraphicsPipelineCreateInfo pipelineCI = {}; + pipelineCI.VertexShader = vertexShader; + pipelineCI.FragmentShader = fragmentShader; + pipelineCI.PrimitiveType = PrimitiveType::TriangleList; + pipelineCI.TargetInfo = { .ColorTargetDescriptions = &colorTargetDescription, + .NumColorTargets = 1, + .DepthStencilFormat = TextureFormat::D32_FLOAT, + .HasDepthStencilTarget = true }; + pipelineCI.RasterizerState.FillMode = FillMode::Solid; + pipelineCI.RasterizerState.CullMode = CullMode::None; + pipelineCI.RasterizerState.FrontFace = FrontFace::Clockwise; + pipelineCI.DepthStencilState.EnableDepthTest = true; + pipelineCI.DepthStencilState.EnableDepthWrite = true; + pipelineCI.DepthStencilState.CompareOperation = CompareOperation::Less; + + g_MeshRenderer.Pipeline = CreateGraphicsPipeline(graphicsDevice, pipelineCI); + if (g_MeshRenderer.Pipeline == nullptr) { - g_MeshRenderer.MeshAssets.Create(assetArena JULIET_DEBUG_PARAM("MeshAssets")); - g_MeshRenderer.MaterialAssets.Create(assetArena JULIET_DEBUG_PARAM("MaterialAssets")); - g_MeshRenderer.MeshInstances.Create(instanceArena JULIET_DEBUG_PARAM("MeshInstances")); - g_MeshRenderer.Vertices.Create(assetArena JULIET_DEBUG_PARAM("Vertices")); - g_MeshRenderer.Indices.Create(assetArena JULIET_DEBUG_PARAM("Indices")); - g_MeshRenderer.PointLights.Create(instanceArena JULIET_DEBUG_PARAM("PointLights")); - - // Create primitives - CubePrimitiveMeshAssetID = CreateCubePrimitive(); - QuadPrimitiveMeshAssetID = CreateQuadPrimitive(); - // SpherePrimitiveMeshAssetID = CreateSpherePrimitive(); // Will implement later - - // Create default material asset (ID = 0) - MaterialAsset defaultMaterial = {}; - g_MeshRenderer.MaterialAssets.PushBack(defaultMaterial); + LogError(LogCategory::Graphics, "Failed to create graphics pipeline!"); + result = false; } - bool InitializeMeshRendererGraphics(NonNullPtr device, NonNullPtr window) + // Create the vertex and index buffers + BufferCreateInfo vertexBufferCI = {}; + vertexBufferCI.Size = kGeometryPage; + vertexBufferCI.Stride = 0; + vertexBufferCI.Usage = BufferUsage::StructuredBuffer; + g_MeshRenderer.VertexBuffer = CreateGraphicsBuffer(graphicsDevice, vertexBufferCI); + Assert(g_MeshRenderer.VertexBuffer != nullptr); + + BufferCreateInfo indexBufferCI = {}; + indexBufferCI.Size = kIndexPage; + indexBufferCI.Usage = BufferUsage::IndexBuffer; + g_MeshRenderer.IndexBuffer = CreateGraphicsBuffer(graphicsDevice, indexBufferCI); + Assert(g_MeshRenderer.IndexBuffer != nullptr); + + // Lights Buffer + BufferCreateInfo lightsBufferCI = {}; + lightsBufferCI.Size = 1024 * sizeof(PointLight); // Max 1024 lights for now + lightsBufferCI.Stride = sizeof(PointLight); + lightsBufferCI.Usage = BufferUsage::StructuredBuffer; + lightsBufferCI.IsDynamic = true; + g_MeshRenderer.LightsBuffer = CreateGraphicsBuffer(graphicsDevice, lightsBufferCI); + Assert(g_MeshRenderer.LightsBuffer != nullptr); + g_MeshRenderer.MappedLights = static_cast(MapGraphicsBuffer(graphicsDevice, g_MeshRenderer.LightsBuffer)); + Assert(g_MeshRenderer.MappedLights != nullptr); + + // Transforms Buffer + BufferCreateInfo transformsBufferCI = {}; + transformsBufferCI.Size = 10000 * sizeof(Matrix); // Max 10000 meshes for now + transformsBufferCI.Stride = sizeof(Matrix); + transformsBufferCI.Usage = BufferUsage::StructuredBuffer; + transformsBufferCI.IsDynamic = true; + g_MeshRenderer.TransformsBuffer = CreateGraphicsBuffer(graphicsDevice, transformsBufferCI); + Assert(g_MeshRenderer.TransformsBuffer != nullptr); + g_MeshRenderer.MappedTransforms = + static_cast(MapGraphicsBuffer(graphicsDevice, g_MeshRenderer.TransformsBuffer)); + Assert(g_MeshRenderer.MappedTransforms != nullptr); + + // Sync existing lights that might have been added before graphics initialization + for (index_t i = 0; i < g_MeshRenderer.PointLights.Count; ++i) { - bool result = true; - - GraphicsDevice* graphicsDevice = g_MeshRenderer.Device = device.Get(); - - // Create graphics pipeline - String entryPoint = WrapString("main"); - ShaderCreateInfo shaderCI = {}; - shaderCI.EntryPoint = entryPoint; - - TempArena path = scratch_begin(0, 0); - - String shaderPath = GetAssetPath(path.Arena, WrapString("Triangle.vert.dxil")); - shaderCI.Stage = ShaderStage::Vertex; - Shader* vertexShader = CreateShader(graphicsDevice, shaderPath, shaderCI); - - shaderPath = GetAssetPath(path.Arena, WrapString("SolidColor.frag.dxil")); - shaderCI.Stage = ShaderStage::Fragment; - Shader* fragmentShader = CreateShader(graphicsDevice, shaderPath, shaderCI); - - scratch_end(path); - - ColorTargetDescription colorTargetDescription = {}; - colorTargetDescription.Format = GetSwapChainTextureFormat(graphicsDevice, window); - - GraphicsPipelineCreateInfo pipelineCI = {}; - pipelineCI.VertexShader = vertexShader; - pipelineCI.FragmentShader = fragmentShader; - pipelineCI.PrimitiveType = PrimitiveType::TriangleList; - pipelineCI.TargetInfo = { .ColorTargetDescriptions = &colorTargetDescription, - .NumColorTargets = 1, - .DepthStencilFormat = TextureFormat::D32_FLOAT, - .HasDepthStencilTarget = true }; - pipelineCI.RasterizerState.FillMode = FillMode::Solid; - pipelineCI.RasterizerState.CullMode = CullMode::None; - pipelineCI.RasterizerState.FrontFace = FrontFace::Clockwise; - pipelineCI.DepthStencilState.EnableDepthTest = true; - pipelineCI.DepthStencilState.EnableDepthWrite = true; - pipelineCI.DepthStencilState.CompareOperation = CompareOperation::Less; - - g_MeshRenderer.Pipeline = CreateGraphicsPipeline(graphicsDevice, pipelineCI); - if (g_MeshRenderer.Pipeline == nullptr) - { - LogError(LogCategory::Graphics, "Failed to create graphics pipeline!"); - result = false; - } - - // Create the vertex and index buffers - BufferCreateInfo vertexBufferCI = {}; - vertexBufferCI.Size = kGeometryPage; - vertexBufferCI.Stride = 0; - vertexBufferCI.Usage = BufferUsage::StructuredBuffer; - g_MeshRenderer.VertexBuffer = CreateGraphicsBuffer(graphicsDevice, vertexBufferCI); - Assert(g_MeshRenderer.VertexBuffer != nullptr); - - BufferCreateInfo indexBufferCI = {}; - indexBufferCI.Size = kIndexPage; - indexBufferCI.Usage = BufferUsage::IndexBuffer; - g_MeshRenderer.IndexBuffer = CreateGraphicsBuffer(graphicsDevice, indexBufferCI); - Assert(g_MeshRenderer.IndexBuffer != nullptr); - - // Lights Buffer - BufferCreateInfo lightsBufferCI = {}; - lightsBufferCI.Size = 1024 * sizeof(PointLight); // Max 1024 lights for now - lightsBufferCI.Stride = sizeof(PointLight); - lightsBufferCI.Usage = BufferUsage::StructuredBuffer; - lightsBufferCI.IsDynamic = true; - g_MeshRenderer.LightsBuffer = CreateGraphicsBuffer(graphicsDevice, lightsBufferCI); - Assert(g_MeshRenderer.LightsBuffer != nullptr); - g_MeshRenderer.MappedLights = static_cast(MapGraphicsBuffer(graphicsDevice, g_MeshRenderer.LightsBuffer)); - Assert(g_MeshRenderer.MappedLights != nullptr); - - // Transforms Buffer - BufferCreateInfo transformsBufferCI = {}; - transformsBufferCI.Size = 10000 * sizeof(Matrix); // Max 10000 meshes for now - transformsBufferCI.Stride = sizeof(Matrix); - transformsBufferCI.Usage = BufferUsage::StructuredBuffer; - transformsBufferCI.IsDynamic = true; - g_MeshRenderer.TransformsBuffer = CreateGraphicsBuffer(graphicsDevice, transformsBufferCI); - Assert(g_MeshRenderer.TransformsBuffer != nullptr); - g_MeshRenderer.MappedTransforms = - static_cast(MapGraphicsBuffer(graphicsDevice, g_MeshRenderer.TransformsBuffer)); - Assert(g_MeshRenderer.MappedTransforms != nullptr); - - // Sync existing lights that might have been added before graphics initialization - for (index_t i = 0; i < g_MeshRenderer.PointLights.Count; ++i) - { - g_MeshRenderer.MappedLights[i] = g_MeshRenderer.PointLights.Data[i]; - } - - if (vertexShader) - { - DestroyShader(graphicsDevice, vertexShader); - } - if (fragmentShader) - { - DestroyShader(graphicsDevice, fragmentShader); - } - - // Load evereything that is already in the vectors - CommandList* loadCmd = AcquireCommandList(device); - LoadMeshesOnGPU(loadCmd); - SubmitCommandLists(loadCmd); - return result; + g_MeshRenderer.MappedLights[i] = g_MeshRenderer.PointLights.Data[i]; } - void ShutdownMeshRendererGraphics() + if (vertexShader) { - if (g_MeshRenderer.LoadCopyBuffer) - { - UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); - DestroyGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); - g_MeshRenderer.LoadCopyBuffer = nullptr; - } - - DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.IndexBuffer); - DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.VertexBuffer); - - if (g_MeshRenderer.LightsBuffer) - { - UnmapGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.LightsBuffer); - DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.LightsBuffer); - g_MeshRenderer.LightsBuffer = nullptr; - } - - if (g_MeshRenderer.TransformsBuffer) - { - UnmapGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.TransformsBuffer); - DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.TransformsBuffer); - g_MeshRenderer.TransformsBuffer = nullptr; - } + DestroyShader(graphicsDevice, vertexShader); + } + if (fragmentShader) + { + DestroyShader(graphicsDevice, fragmentShader); } - void ShutdownMeshRenderer() + // Load evereything that is already in the vectors + CommandList* loadCmd = AcquireCommandList(device); + LoadMeshesOnGPU(loadCmd); + SubmitCommandLists(loadCmd); + return result; +} + +void ShutdownMeshRendererGraphics() +{ + if (g_MeshRenderer.LoadCopyBuffer) { - g_MeshRenderer.Indices.Destroy(); - g_MeshRenderer.Vertices.Destroy(); - g_MeshRenderer.MeshInstances.Destroy(); - g_MeshRenderer.MaterialAssets.Destroy(); - g_MeshRenderer.MeshAssets.Destroy(); - g_MeshRenderer.PointLights.Destroy(); - } - - void LoadMeshesOnGPU(NonNullPtr cmdList) - { - if (g_MeshRenderer.MeshAssets.IsEmpty()) - { - return; - } - - // Loading everything in one go. - // Destroy the buffer at the end - - TransferBufferCreateInfo uploadBCI = {}; - uploadBCI.Usage = TransferBufferUsage::Upload; - uploadBCI.Size = kGeometryPage + kIndexPage; - g_MeshRenderer.LoadCopyBuffer = CreateGraphicsTransferBuffer(g_MeshRenderer.Device, uploadBCI); - - void* map = MapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); - - Vertex* vertices = g_MeshRenderer.Vertices.Data; - if (!vertices) - { - UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); - DestroyGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); - g_MeshRenderer.LoadCopyBuffer = nullptr; - return; - } - - Index* indices = g_MeshRenderer.Indices.Data; - if (!indices) - { - UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); - DestroyGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); - g_MeshRenderer.LoadCopyBuffer = nullptr; - return; - } - - // Copy all meshes! This supports only one page for now - // Copy ALL Vertices in one block - size_t totalVertexBytes = g_MeshRenderer.Vertices.Count * sizeof(Vertex); - MemCopy(map, g_MeshRenderer.Vertices.Data, totalVertexBytes); - - // Copy ALL Indices in one block - size_t indexOfByteOffset = (kGeometryPage + 255) & static_cast(~255); - uint8* ptrOneByte = static_cast(map); - size_t totalIndexBytes = g_MeshRenderer.Indices.Count * sizeof(Index); - - MemCopy(ptrOneByte + indexOfByteOffset, g_MeshRenderer.Indices.Data, totalIndexBytes); - UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); - - CopyBuffer(cmdList, g_MeshRenderer.VertexBuffer, g_MeshRenderer.LoadCopyBuffer, totalVertexBytes, 0, 0); - CopyBuffer(cmdList, g_MeshRenderer.IndexBuffer, g_MeshRenderer.LoadCopyBuffer, totalIndexBytes, 0, indexOfByteOffset); - - // Transition vertex buffer to SRV state (this barrier waits for copy to complete) - TransitionBufferToReadable(cmdList, g_MeshRenderer.VertexBuffer); - TransitionBufferToReadable(cmdList, g_MeshRenderer.IndexBuffer); + DestroyGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); + g_MeshRenderer.LoadCopyBuffer = nullptr; } - void RenderMeshes(NonNullPtr cmdList, NonNullPtr pass, const Matrix& viewProjection) + DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.IndexBuffer); + DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.VertexBuffer); + + if (g_MeshRenderer.LightsBuffer) { - // First destroy any buffer that needs to be - if (g_MeshRenderer.LoadCopyBuffer) + UnmapGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.LightsBuffer); + DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.LightsBuffer); + g_MeshRenderer.LightsBuffer = nullptr; + } + + if (g_MeshRenderer.TransformsBuffer) + { + UnmapGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.TransformsBuffer); + DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.TransformsBuffer); + g_MeshRenderer.TransformsBuffer = nullptr; + } +} + +void ShutdownMeshRenderer() +{ + g_MeshRenderer.Indices.Destroy(); + g_MeshRenderer.Vertices.Destroy(); + g_MeshRenderer.MeshInstances.Destroy(); + g_MeshRenderer.MaterialAssets.Destroy(); + g_MeshRenderer.MeshAssets.Destroy(); + g_MeshRenderer.PointLights.Destroy(); +} + +void LoadMeshesOnGPU(NonNullPtr cmdList) +{ + if (g_MeshRenderer.MeshAssets.IsEmpty()) + { + return; + } + + // Loading everything in one go. + // Destroy the buffer at the end + + TransferBufferCreateInfo uploadBCI = {}; + uploadBCI.Usage = TransferBufferUsage::Upload; + uploadBCI.Size = kGeometryPage + kIndexPage; + g_MeshRenderer.LoadCopyBuffer = CreateGraphicsTransferBuffer(g_MeshRenderer.Device, uploadBCI); + + void* map = MapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); + + Vertex* vertices = g_MeshRenderer.Vertices.Data; + if (!vertices) + { + UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); + DestroyGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); + g_MeshRenderer.LoadCopyBuffer = nullptr; + return; + } + + Index* indices = g_MeshRenderer.Indices.Data; + if (!indices) + { + UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); + DestroyGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); + g_MeshRenderer.LoadCopyBuffer = nullptr; + return; + } + + // Copy all meshes! This supports only one page for now + // Copy ALL Vertices in one block + size_t totalVertexBytes = g_MeshRenderer.Vertices.Count * sizeof(Vertex); + MemCopy(map, g_MeshRenderer.Vertices.Data, totalVertexBytes); + + // Copy ALL Indices in one block + size_t indexOfByteOffset = (kGeometryPage + 255) & static_cast(~255); + uint8* ptrOneByte = static_cast(map); + size_t totalIndexBytes = g_MeshRenderer.Indices.Count * sizeof(Index); + + MemCopy(ptrOneByte + indexOfByteOffset, g_MeshRenderer.Indices.Data, totalIndexBytes); + + UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); + + CopyBuffer(cmdList, g_MeshRenderer.VertexBuffer, g_MeshRenderer.LoadCopyBuffer, totalVertexBytes, 0, 0); + CopyBuffer(cmdList, g_MeshRenderer.IndexBuffer, g_MeshRenderer.LoadCopyBuffer, totalIndexBytes, 0, indexOfByteOffset); + + // Transition vertex buffer to SRV state (this barrier waits for copy to complete) + TransitionBufferToReadable(cmdList, g_MeshRenderer.VertexBuffer); + TransitionBufferToReadable(cmdList, g_MeshRenderer.IndexBuffer); +} + +void RenderMeshes(NonNullPtr cmdList, NonNullPtr pass, const Matrix& viewProjection) +{ + // First destroy any buffer that needs to be + if (g_MeshRenderer.LoadCopyBuffer) + { + WaitUntilGPUIsIdle(g_MeshRenderer.Device); + UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); + DestroyGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); + g_MeshRenderer.LoadCopyBuffer = nullptr; + } + + BindGraphicsPipeline(pass, g_MeshRenderer.Pipeline); + + uint32 vertexDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.VertexBuffer); + uint32 lightDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.LightsBuffer); + + uint32 transformsDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.TransformsBuffer); + + PushData pushData = {}; + pushData.ViewProjection = viewProjection; + pushData.BufferIndex = vertexDescriptorIndex; + pushData.LightBufferIndex = lightDescriptorIndex; + pushData.TransformsBufferIndex = transformsDescriptorIndex; + pushData.ActiveLightCount = static_cast(g_MeshRenderer.PointLights.Count); + pushData.GlobalLightDirection = g_MeshRenderer.GlobalLightDirection; + pushData.GlobalLightColor = g_MeshRenderer.GlobalLightColor; + pushData.GlobalAmbientIntensity = g_MeshRenderer.GlobalAmbientIntensity; + + SetIndexBuffer(cmdList, g_MeshRenderer.IndexBuffer, IndexFormat::UInt16, g_MeshRenderer.Indices.Count, 0); + + uint32 meshIndex = 0; + for (MeshInstance& instance : g_MeshRenderer.MeshInstances) + { + if (g_MeshRenderer.MappedTransforms) { - WaitUntilGPUIsIdle(g_MeshRenderer.Device); - UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); - DestroyGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer); - g_MeshRenderer.LoadCopyBuffer = nullptr; + g_MeshRenderer.MappedTransforms[meshIndex] = instance.Transform; } - BindGraphicsPipeline(pass, g_MeshRenderer.Pipeline); + MeshAsset& meshAsset = g_MeshRenderer.MeshAssets.Data[instance.MeshAsset]; + MaterialAsset& materialAsset = g_MeshRenderer.MaterialAssets.Data[instance.MaterialAsset]; - uint32 vertexDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.VertexBuffer); - uint32 lightDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.LightsBuffer); + pushData.MeshIndex = meshIndex; + pushData.TextureIndex = 0; // Would be instance.MaterialAsset.BaseColorTexture later + pushData.VertexOffset = static_cast(meshAsset.VertexOffset); + pushData.Scale[0] = 1.0f; + pushData.Scale[1] = 1.0f; + pushData.Translate[0] = 0.0f; + pushData.Translate[1] = 0.0f; + pushData.MeshAlbedo = materialAsset.AlbedoColor; + SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData); + DrawIndexedPrimitives(pass, static_cast(meshAsset.IndexCount), 1, + static_cast(meshAsset.IndexOffset), static_cast(meshAsset.VertexOffset), 0); + meshIndex++; + } +} - uint32 transformsDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.TransformsBuffer); +LightID AddPointLight(const PointLight& light) +{ + Assert(g_MeshRenderer.PointLights.Count < kDefaultLightCount); + LightID id = g_MeshRenderer.PointLights.Count; + g_MeshRenderer.PointLights.PushBack(light); + if (g_MeshRenderer.MappedLights) + { + g_MeshRenderer.MappedLights[id] = light; + } + return id; +} - PushData pushData = {}; - pushData.ViewProjection = viewProjection; - pushData.BufferIndex = vertexDescriptorIndex; - pushData.LightBufferIndex = lightDescriptorIndex; - pushData.TransformsBufferIndex = transformsDescriptorIndex; - pushData.ActiveLightCount = static_cast(g_MeshRenderer.PointLights.Count); - pushData.GlobalLightDirection = g_MeshRenderer.GlobalLightDirection; - pushData.GlobalLightColor = g_MeshRenderer.GlobalLightColor; - pushData.GlobalAmbientIntensity = g_MeshRenderer.GlobalAmbientIntensity; +void SetPointLightPosition(LightID id, const Vector3& position) +{ + Assert(id < static_cast(g_MeshRenderer.PointLights.Count)); + g_MeshRenderer.PointLights.Data[id].Position = position; + if (g_MeshRenderer.MappedLights) + { + g_MeshRenderer.MappedLights[id].Position = position; + } +} - SetIndexBuffer(cmdList, g_MeshRenderer.IndexBuffer, IndexFormat::UInt16, g_MeshRenderer.Indices.Count, 0); +void SetPointLightColor(LightID id, const Vector3& color) +{ + Assert(id < static_cast(g_MeshRenderer.PointLights.Count)); + g_MeshRenderer.PointLights.Data[id].Color = color; + if (g_MeshRenderer.MappedLights) + { + g_MeshRenderer.MappedLights[id].Color = color; + } +} - uint32 meshIndex = 0; - for (MeshInstance& instance : g_MeshRenderer.MeshInstances) +void SetPointLightRadius(LightID id, float radius) +{ + Assert(id < static_cast(g_MeshRenderer.PointLights.Count)); + g_MeshRenderer.PointLights.Data[id].Radius = radius; + if (g_MeshRenderer.MappedLights) + { + g_MeshRenderer.MappedLights[id].Radius = radius; + } +} + +void SetPointLightIntensity(LightID id, float intensity) +{ + Assert(id < static_cast(g_MeshRenderer.PointLights.Count)); + g_MeshRenderer.PointLights.Data[id].Intensity = intensity; + if (g_MeshRenderer.MappedLights) + { + g_MeshRenderer.MappedLights[id].Intensity = intensity; + } +} + +void ClearPointLights() +{ + g_MeshRenderer.PointLights.Clear(); +} + +void SetGlobalLight(const Vector3& direction, const Vector3& color, float ambientIntensity) +{ + g_MeshRenderer.GlobalLightDirection = direction; + g_MeshRenderer.GlobalLightColor = color; + g_MeshRenderer.GlobalAmbientIntensity = ambientIntensity; +} + +MeshAssetID GetCubePrimitiveMeshAssetID() +{ + Assert(CubePrimitiveMeshAssetID != static_cast(-1)); + return CubePrimitiveMeshAssetID; +} + +MeshAssetID GetQuadPrimitiveMeshAssetID() +{ + Assert(QuadPrimitiveMeshAssetID != static_cast(-1)); + return QuadPrimitiveMeshAssetID; +} + +MeshAssetID GetSpherePrimitiveMeshAssetID() +{ + Assert(SpherePrimitiveMeshAssetID != static_cast(-1)); + return SpherePrimitiveMeshAssetID; +} + +MeshAssetID GetOrCreateMeshAsset(String name) +{ + for (index_t i = 0; i < g_MeshRenderer.MeshAssets.Count; ++i) + { + if (StringCompare(g_MeshRenderer.MeshAssets.Data[i].Name, name) == 0) { - if (g_MeshRenderer.MappedTransforms) - { - g_MeshRenderer.MappedTransforms[meshIndex] = instance.Transform; - } - - MeshAsset& meshAsset = g_MeshRenderer.MeshAssets.Data[instance.MeshAsset]; - MaterialAsset& materialAsset = g_MeshRenderer.MaterialAssets.Data[instance.MaterialAsset]; - - pushData.MeshIndex = meshIndex; - pushData.TextureIndex = 0; // Would be instance.MaterialAsset.BaseColorTexture later - pushData.VertexOffset = static_cast(meshAsset.VertexOffset); - pushData.Scale[0] = 1.0f; - pushData.Scale[1] = 1.0f; - pushData.Translate[0] = 0.0f; - pushData.Translate[1] = 0.0f; - pushData.MeshAlbedo = materialAsset.AlbedoColor; - SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData); - DrawIndexedPrimitives(pass, static_cast(meshAsset.IndexCount), 1, - static_cast(meshAsset.IndexOffset), static_cast(meshAsset.VertexOffset), 0); - meshIndex++; + return i; } } - LightID AddPointLight(const PointLight& light) - { - Assert(g_MeshRenderer.PointLights.Count < kDefaultLightCount); - LightID id = g_MeshRenderer.PointLights.Count; - g_MeshRenderer.PointLights.PushBack(light); - if (g_MeshRenderer.MappedLights) - { - g_MeshRenderer.MappedLights[id] = light; - } - return id; - } + return LoadMesh(name); +} - void SetPointLightPosition(LightID id, const Vector3& position) - { - Assert(id < static_cast(g_MeshRenderer.PointLights.Count)); - g_MeshRenderer.PointLights.Data[id].Position = position; - if (g_MeshRenderer.MappedLights) - { - g_MeshRenderer.MappedLights[id].Position = position; - } - } +MeshInstanceID CreateMeshInstance(MeshAssetID meshAsset, MaterialAssetID materialAsset, const Matrix& transform) +{ + MeshInstance instance = {}; + instance.MeshAsset = meshAsset; + instance.MaterialAsset = materialAsset; + instance.Transform = transform; + MeshInstanceID id = g_MeshRenderer.MeshInstances.Count; + g_MeshRenderer.MeshInstances.PushBack(instance); + return id; +} - void SetPointLightColor(LightID id, const Vector3& color) - { - Assert(id < static_cast(g_MeshRenderer.PointLights.Count)); - g_MeshRenderer.PointLights.Data[id].Color = color; - if (g_MeshRenderer.MappedLights) - { - g_MeshRenderer.MappedLights[id].Color = color; - } - } +void SetMeshInstanceTransform(MeshInstanceID id, const Matrix& transform) +{ + Assert(id < static_cast(g_MeshRenderer.MeshInstances.Count)); + g_MeshRenderer.MeshInstances.Data[id].Transform = transform; +} - void SetPointLightRadius(LightID id, float radius) - { - Assert(id < static_cast(g_MeshRenderer.PointLights.Count)); - g_MeshRenderer.PointLights.Data[id].Radius = radius; - if (g_MeshRenderer.MappedLights) - { - g_MeshRenderer.MappedLights[id].Radius = radius; - } - } +MeshAssetID CreateCubePrimitive() +{ + MeshAsset result = {}; + result.Name = WrapString("Cube"); - void SetPointLightIntensity(LightID id, float intensity) - { - Assert(id < static_cast(g_MeshRenderer.PointLights.Count)); - g_MeshRenderer.PointLights.Data[id].Intensity = intensity; - if (g_MeshRenderer.MappedLights) - { - g_MeshRenderer.MappedLights[id].Intensity = intensity; - } - } + constexpr Vertex vertexData[] = { // Front Face (Z = -0.5f) — Red + { { -0.5f, 0.5f, -0.5f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { 0.5f, 0.5f, -0.5f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { 0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { -0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - void ClearPointLights() - { - g_MeshRenderer.PointLights.Clear(); - } + // Back Face (Z = 0.5f) — Green + { { 0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { -0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { -0.5f, -0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { 0.5f, -0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - void SetGlobalLight(const Vector3& direction, const Vector3& color, float ambientIntensity) - { - g_MeshRenderer.GlobalLightDirection = direction; - g_MeshRenderer.GlobalLightColor = color; - g_MeshRenderer.GlobalAmbientIntensity = ambientIntensity; - } + // Top Face (Y = 0.5f) — Blue + { { -0.5f, 0.5f, 0.5f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { 0.5f, 0.5f, 0.5f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { 0.5f, 0.5f, -0.5f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { -0.5f, 0.5f, -0.5f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - MeshAssetID GetCubePrimitiveMeshAssetID() - { - Assert(CubePrimitiveMeshAssetID != static_cast(-1)); - return CubePrimitiveMeshAssetID; - } + // Bottom Face (Y = -0.5f) — Yellow + { { -0.5f, -0.5f, -0.5f }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { 0.5f, -0.5f, -0.5f }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { 0.5f, -0.5f, 0.5f }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { -0.5f, -0.5f, 0.5f }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - MeshAssetID GetQuadPrimitiveMeshAssetID() - { - Assert(QuadPrimitiveMeshAssetID != static_cast(-1)); - return QuadPrimitiveMeshAssetID; - } + // Right Face (X = 0.5f) — Cyan + { { 0.5f, 0.5f, -0.5f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { 0.5f, 0.5f, 0.5f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { 0.5f, -0.5f, 0.5f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { 0.5f, -0.5f, -0.5f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - MeshAssetID GetSpherePrimitiveMeshAssetID() - { - Assert(SpherePrimitiveMeshAssetID != static_cast(-1)); - return SpherePrimitiveMeshAssetID; - } + // Left Face (X = -0.5f) — Magenta + { { -0.5f, 0.5f, 0.5f }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { -0.5f, 0.5f, -0.5f }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { -0.5f, -0.5f, -0.5f }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + { { -0.5f, -0.5f, 0.5f }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } } + }; + constexpr size_t cubeVertexCount = ArraySize(vertexData); + result.VertexCount = cubeVertexCount; + result.VertexOffset = g_MeshRenderer.Vertices.Count; + g_MeshRenderer.Vertices.PushBack(vertexData, cubeVertexCount); - MeshAssetID GetOrCreateMeshAsset(String name) - { - for (index_t i = 0; i < g_MeshRenderer.MeshAssets.Count; ++i) - { - if (StringCompare(g_MeshRenderer.MeshAssets.Data[i].Name, name) == 0) - { - return i; - } - } + constexpr uint16 indices[] = { 0, 1, 2, 0, 2, 3, // Front + 4, 5, 6, 4, 6, 7, // Back + 8, 9, 10, 8, 10, 11, // Top + 12, 13, 14, 12, 14, 15, // Bottom + 16, 17, 18, 16, 18, 19, // Right + 20, 21, 22, 20, 22, 23 }; // Left + constexpr size_t indexCubeCount = ArraySize(indices); + result.IndexCount = indexCubeCount; + result.IndexOffset = g_MeshRenderer.Indices.Count; + g_MeshRenderer.Indices.PushBack(indices, indexCubeCount); - return LoadMesh(name); - } + MeshAssetID id = g_MeshRenderer.MeshAssets.Count; + g_MeshRenderer.MeshAssets.PushBack(result); + return id; +} - MeshInstanceID CreateMeshInstance(MeshAssetID meshAsset, MaterialAssetID materialAsset, const Matrix& transform) - { - MeshInstance instance = {}; - instance.MeshAsset = meshAsset; - instance.MaterialAsset = materialAsset; - instance.Transform = transform; - MeshInstanceID id = g_MeshRenderer.MeshInstances.Count; - g_MeshRenderer.MeshInstances.PushBack(instance); - return id; - } +MeshAssetID CreateQuadPrimitive() +{ + MeshAsset result = {}; + result.Name = WrapString("Quad"); - void SetMeshInstanceTransform(MeshInstanceID id, const Matrix& transform) - { - Assert(id < static_cast(g_MeshRenderer.MeshInstances.Count)); - g_MeshRenderer.MeshInstances.Data[id].Transform = transform; - } + constexpr Vertex vertexData[] = { + // Triangle 1 (Clockwise) + { { -0.5f, -0.5f, 0.0f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, // 0 + { { 0.0f, 0.5f, 0.0f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, // 1 + { { 0.5f, -0.5f, 0.0f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, // 2 - MeshAssetID CreateCubePrimitive() - { - MeshAsset result = {}; - result.Name = WrapString("Cube"); + // Triangle 2 (Clockwise) + { { -0.5f, 0.5f, 0.0f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, // 3 + { { 0.0f, 0.8f, 0.0f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, // 4 + { { 0.5f, 0.5f, 0.0f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } } // 5 + }; + constexpr size_t triVertexCount = ArraySize(vertexData); + result.VertexCount = triVertexCount; + result.VertexOffset = g_MeshRenderer.Vertices.Count; + g_MeshRenderer.Vertices.PushBack(vertexData, triVertexCount); - constexpr Vertex vertexData[] = { // Front Face (Z = -0.5f) — Red - { { -0.5f, 0.5f, -0.5f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { 0.5f, 0.5f, -0.5f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { 0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { -0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + constexpr uint16 indices[] = { 0, 1, 2, 3, 4, 5 }; + constexpr size_t triIndexCount = ArraySize(indices); + result.IndexCount = triIndexCount; + result.IndexOffset = g_MeshRenderer.Indices.Count; + g_MeshRenderer.Indices.PushBack(indices, triIndexCount); - // Back Face (Z = 0.5f) — Green - { { 0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { -0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { -0.5f, -0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { 0.5f, -0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, + MeshAssetID id = g_MeshRenderer.MeshAssets.Count; + g_MeshRenderer.MeshAssets.PushBack(result); + return id; +} - // Top Face (Y = 0.5f) — Blue - { { -0.5f, 0.5f, 0.5f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { 0.5f, 0.5f, 0.5f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { 0.5f, 0.5f, -0.5f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { -0.5f, 0.5f, -0.5f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - - // Bottom Face (Y = -0.5f) — Yellow - { { -0.5f, -0.5f, -0.5f }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { 0.5f, -0.5f, -0.5f }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { 0.5f, -0.5f, 0.5f }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { -0.5f, -0.5f, 0.5f }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - - // Right Face (X = 0.5f) — Cyan - { { 0.5f, 0.5f, -0.5f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { 0.5f, 0.5f, 0.5f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { 0.5f, -0.5f, 0.5f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { 0.5f, -0.5f, -0.5f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - - // Left Face (X = -0.5f) — Magenta - { { -0.5f, 0.5f, 0.5f }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { -0.5f, 0.5f, -0.5f }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { -0.5f, -0.5f, -0.5f }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, - { { -0.5f, -0.5f, 0.5f }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } } - }; - constexpr size_t cubeVertexCount = ArraySize(vertexData); - result.VertexCount = cubeVertexCount; - result.VertexOffset = g_MeshRenderer.Vertices.Count; - g_MeshRenderer.Vertices.PushBack(vertexData, cubeVertexCount); - - constexpr uint16 indices[] = { 0, 1, 2, 0, 2, 3, // Front - 4, 5, 6, 4, 6, 7, // Back - 8, 9, 10, 8, 10, 11, // Top - 12, 13, 14, 12, 14, 15, // Bottom - 16, 17, 18, 16, 18, 19, // Right - 20, 21, 22, 20, 22, 23 }; // Left - constexpr size_t indexCubeCount = ArraySize(indices); - result.IndexCount = indexCubeCount; - result.IndexOffset = g_MeshRenderer.Indices.Count; - g_MeshRenderer.Indices.PushBack(indices, indexCubeCount); - - MeshAssetID id = g_MeshRenderer.MeshAssets.Count; - g_MeshRenderer.MeshAssets.PushBack(result); - return id; - } - - MeshAssetID CreateQuadPrimitive() - { - MeshAsset result = {}; - result.Name = WrapString("Quad"); - - constexpr Vertex vertexData[] = { - // Triangle 1 (Clockwise) - { { -0.5f, -0.5f, 0.0f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, // 0 - { { 0.0f, 0.5f, 0.0f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, // 1 - { { 0.5f, -0.5f, 0.0f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, // 2 - - // Triangle 2 (Clockwise) - { { -0.5f, 0.5f, 0.0f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, // 3 - { { 0.0f, 0.8f, 0.0f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, // 4 - { { 0.5f, 0.5f, 0.0f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } } // 5 - }; - constexpr size_t triVertexCount = ArraySize(vertexData); - result.VertexCount = triVertexCount; - result.VertexOffset = g_MeshRenderer.Vertices.Count; - g_MeshRenderer.Vertices.PushBack(vertexData, triVertexCount); - - constexpr uint16 indices[] = { 0, 1, 2, 3, 4, 5 }; - constexpr size_t triIndexCount = ArraySize(indices); - result.IndexCount = triIndexCount; - result.IndexOffset = g_MeshRenderer.Indices.Count; - g_MeshRenderer.Indices.PushBack(indices, triIndexCount); - - MeshAssetID id = g_MeshRenderer.MeshAssets.Count; - g_MeshRenderer.MeshAssets.PushBack(result); - return id; - } - - // Sphere primitive implementation omitted for brevity, returning Cube for now if called. - MeshAssetID CreateSpherePrimitive() - { - // Just returning cube for now until proper sphere generation is written - MeshAssetID id = CreateCubePrimitive(); - g_MeshRenderer.MeshAssets.Data[id].Name = WrapString("Sphere"); // Rename just to pass cache - return id; - } +// Sphere primitive implementation omitted for brevity, returning Cube for now if called. +MeshAssetID CreateSpherePrimitive() +{ + // Just returning cube for now until proper sphere generation is written + MeshAssetID id = CreateCubePrimitive(); + g_MeshRenderer.MeshAssets.Data[id].Name = WrapString("Sphere"); // Rename just to pass cache + return id; +} #if ALLOW_SHADER_HOT_RELOAD - void ReloadMeshRendererShaders() +void ReloadMeshRendererShaders() +{ + auto* pipeline = g_MeshRenderer.Pipeline; + auto* device = g_MeshRenderer.Device; + + TempArena path = scratch_begin(0, 0); + + String entryPoint = WrapString("main"); + ShaderCreateInfo shaderCI = {}; + shaderCI.EntryPoint = entryPoint; + String shaderPath = GetAssetPath(path.Arena, WrapString("Triangle.vert.dxil")); + shaderCI.Stage = ShaderStage::Vertex; + Shader* vertexShader = CreateShader(device, shaderPath, shaderCI); + + shaderPath = GetAssetPath(path.Arena, WrapString("SolidColor.frag.dxil")); + shaderCI.Stage = ShaderStage::Fragment; + Shader* fragmentShader = CreateShader(device, shaderPath, shaderCI); + + scratch_end(path); + + UpdateGraphicsPipelineShaders(device, pipeline, vertexShader, fragmentShader); + + if (vertexShader) { - auto* pipeline = g_MeshRenderer.Pipeline; - auto* device = g_MeshRenderer.Device; - - TempArena path = scratch_begin(0, 0); - - String entryPoint = WrapString("main"); - ShaderCreateInfo shaderCI = {}; - shaderCI.EntryPoint = entryPoint; - String shaderPath = GetAssetPath(path.Arena, WrapString("Triangle.vert.dxil")); - shaderCI.Stage = ShaderStage::Vertex; - Shader* vertexShader = CreateShader(device, shaderPath, shaderCI); - - shaderPath = GetAssetPath(path.Arena, WrapString("SolidColor.frag.dxil")); - shaderCI.Stage = ShaderStage::Fragment; - Shader* fragmentShader = CreateShader(device, shaderPath, shaderCI); - - scratch_end(path); - - UpdateGraphicsPipelineShaders(device, pipeline, vertexShader, fragmentShader); - - if (vertexShader) - { - DestroyShader(device, vertexShader); - } - if (fragmentShader) - { - DestroyShader(device, fragmentShader); - } + DestroyShader(device, vertexShader); } + if (fragmentShader) + { + DestroyShader(device, fragmentShader); + } +} #endif -} // namespace Juliet diff --git a/Juliet/src/Graphics/SkyboxRenderer.cpp b/Juliet/src/Graphics/SkyboxRenderer.cpp index dacf06d..c1e920c 100644 --- a/Juliet/src/Graphics/SkyboxRenderer.cpp +++ b/Juliet/src/Graphics/SkyboxRenderer.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -7,109 +7,106 @@ #include #include -namespace Juliet +namespace { - namespace + SkyboxRenderer g_SkyboxRenderer; +} // namespace + +bool InitializeSkyboxRenderer(NonNullPtr device, NonNullPtr window) +{ + bool result = true; + + GraphicsDevice* graphicsDevice = g_SkyboxRenderer.Device = device.Get(); + + TempArena path = scratch_begin(0, 0); + + String skyboxVSEntry = WrapString("main"); + ShaderCreateInfo skyboxVSCI = {}; + skyboxVSCI.EntryPoint = skyboxVSEntry; + skyboxVSCI.Stage = ShaderStage::Vertex; + String vsPath = GetAssetPath(path.Arena, WrapString("Skybox.vert.dxil")); + Shader* skyboxVS = CreateShader(graphicsDevice, vsPath, skyboxVSCI); + + String skyboxFSEntry = WrapString("main"); + ShaderCreateInfo skyboxFSCI = {}; + skyboxFSCI.EntryPoint = skyboxFSEntry; + skyboxFSCI.Stage = ShaderStage::Fragment; + String fsPath = GetAssetPath(path.Arena, WrapString("Skybox.frag.dxil")); + Shader* skyboxFS = CreateShader(graphicsDevice, fsPath, skyboxFSCI); + + scratch_end(path); + + ColorTargetDescription colorTargetDesc = {}; + colorTargetDesc.Format = GetSwapChainTextureFormat(graphicsDevice, window); + + GraphicsPipelineCreateInfo skyboxPipelineCI = {}; + skyboxPipelineCI.VertexShader = skyboxVS; + skyboxPipelineCI.FragmentShader = skyboxFS; + skyboxPipelineCI.PrimitiveType = PrimitiveType::TriangleList; + skyboxPipelineCI.TargetInfo.ColorTargetDescriptions = &colorTargetDesc; + skyboxPipelineCI.TargetInfo.NumColorTargets = 1; + skyboxPipelineCI.TargetInfo.DepthStencilFormat = TextureFormat::D32_FLOAT; + skyboxPipelineCI.TargetInfo.HasDepthStencilTarget = true; + skyboxPipelineCI.RasterizerState.FillMode = FillMode::Solid; + skyboxPipelineCI.RasterizerState.CullMode = CullMode::None; + skyboxPipelineCI.RasterizerState.FrontFace = FrontFace::Clockwise; + skyboxPipelineCI.DepthStencilState.EnableDepthTest = true; + skyboxPipelineCI.DepthStencilState.EnableDepthWrite = false; + skyboxPipelineCI.DepthStencilState.CompareOperation = CompareOperation::LessOrEqual; + + g_SkyboxRenderer.Pipeline = CreateGraphicsPipeline(graphicsDevice, skyboxPipelineCI); + if (g_SkyboxRenderer.Pipeline == nullptr) { - SkyboxRenderer g_SkyboxRenderer; - } // namespace - - bool InitializeSkyboxRenderer(NonNullPtr device, NonNullPtr window) - { - bool result = true; - - GraphicsDevice* graphicsDevice = g_SkyboxRenderer.Device = device.Get(); - - TempArena path = scratch_begin(0, 0); - - String skyboxVSEntry = WrapString("main"); - ShaderCreateInfo skyboxVSCI = {}; - skyboxVSCI.EntryPoint = skyboxVSEntry; - skyboxVSCI.Stage = ShaderStage::Vertex; - String vsPath = GetAssetPath(path.Arena, WrapString("Skybox.vert.dxil")); - Shader* skyboxVS = CreateShader(graphicsDevice, vsPath, skyboxVSCI); - - String skyboxFSEntry = WrapString("main"); - ShaderCreateInfo skyboxFSCI = {}; - skyboxFSCI.EntryPoint = skyboxFSEntry; - skyboxFSCI.Stage = ShaderStage::Fragment; - String fsPath = GetAssetPath(path.Arena, WrapString("Skybox.frag.dxil")); - Shader* skyboxFS = CreateShader(graphicsDevice, fsPath, skyboxFSCI); - - scratch_end(path); - - ColorTargetDescription colorTargetDesc = {}; - colorTargetDesc.Format = GetSwapChainTextureFormat(graphicsDevice, window); - - GraphicsPipelineCreateInfo skyboxPipelineCI = {}; - skyboxPipelineCI.VertexShader = skyboxVS; - skyboxPipelineCI.FragmentShader = skyboxFS; - skyboxPipelineCI.PrimitiveType = PrimitiveType::TriangleList; - skyboxPipelineCI.TargetInfo.ColorTargetDescriptions = &colorTargetDesc; - skyboxPipelineCI.TargetInfo.NumColorTargets = 1; - skyboxPipelineCI.TargetInfo.DepthStencilFormat = TextureFormat::D32_FLOAT; - skyboxPipelineCI.TargetInfo.HasDepthStencilTarget = true; - skyboxPipelineCI.RasterizerState.FillMode = FillMode::Solid; - skyboxPipelineCI.RasterizerState.CullMode = CullMode::None; - skyboxPipelineCI.RasterizerState.FrontFace = FrontFace::Clockwise; - skyboxPipelineCI.DepthStencilState.EnableDepthTest = true; - skyboxPipelineCI.DepthStencilState.EnableDepthWrite = false; - skyboxPipelineCI.DepthStencilState.CompareOperation = CompareOperation::LessOrEqual; - - g_SkyboxRenderer.Pipeline = CreateGraphicsPipeline(graphicsDevice, skyboxPipelineCI); - if (g_SkyboxRenderer.Pipeline == nullptr) - { - LogError(LogCategory::Graphics, "Failed to create skybox pipeline!"); - result = false; - } - - if (skyboxVS) - { - DestroyShader(graphicsDevice, skyboxVS); - } - if (skyboxFS) - { - DestroyShader(graphicsDevice, skyboxFS); - } - - return result; + LogError(LogCategory::Graphics, "Failed to create skybox pipeline!"); + result = false; } - void ShutdownSkyboxRenderer() + if (skyboxVS) { - if (g_SkyboxRenderer.Pipeline) - { - DestroyGraphicsPipeline(g_SkyboxRenderer.Device, g_SkyboxRenderer.Pipeline); - g_SkyboxRenderer.Pipeline = nullptr; - } - - g_SkyboxRenderer = {}; + DestroyShader(graphicsDevice, skyboxVS); + } + if (skyboxFS) + { + DestroyShader(graphicsDevice, skyboxFS); } - void RenderSkybox(NonNullPtr cmdList, NonNullPtr pass, const Matrix& viewProjection) + return result; +} + +void ShutdownSkyboxRenderer() +{ + if (g_SkyboxRenderer.Pipeline) { - if (!g_SkyboxRenderer.Pipeline) - { - return; - } - - PushData pushData = {}; - pushData.ViewProjection = viewProjection; - pushData.MeshIndex = 0; - pushData.TransformsBufferIndex = 0; - pushData.BufferIndex = 0; - - BindGraphicsPipeline(pass, g_SkyboxRenderer.Pipeline); - SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData); - SetPushConstants(cmdList, ShaderStage::Fragment, 0, sizeof(pushData) / 4, &pushData); - DrawPrimitives(pass, 3, 1, 0, 0); + DestroyGraphicsPipeline(g_SkyboxRenderer.Device, g_SkyboxRenderer.Pipeline); + g_SkyboxRenderer.Pipeline = nullptr; } + g_SkyboxRenderer = {}; +} + +void RenderSkybox(NonNullPtr cmdList, NonNullPtr pass, const Matrix& viewProjection) +{ + if (!g_SkyboxRenderer.Pipeline) + { + return; + } + + PushData pushData = {}; + pushData.ViewProjection = viewProjection; + pushData.MeshIndex = 0; + pushData.TransformsBufferIndex = 0; + pushData.BufferIndex = 0; + + BindGraphicsPipeline(pass, g_SkyboxRenderer.Pipeline); + SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData); + SetPushConstants(cmdList, ShaderStage::Fragment, 0, sizeof(pushData) / 4, &pushData); + DrawPrimitives(pass, 3, 1, 0, 0); +} + #if ALLOW_SHADER_HOT_RELOAD - void ReloadSkyboxShaders() - { - // TODO - } +void ReloadSkyboxShaders() +{ + // TODO +} #endif -} // namespace Juliet diff --git a/Juliet/src/UnitTest/Container/VectorUnitTest.cpp b/Juliet/src/UnitTest/Container/VectorUnitTest.cpp index 4a5c951..b89066e 100644 --- a/Juliet/src/UnitTest/Container/VectorUnitTest.cpp +++ b/Juliet/src/UnitTest/Container/VectorUnitTest.cpp @@ -1,10 +1,10 @@ -#include +#include #if JULIET_DEBUG #include #include -namespace Juliet::UnitTest +namespace UnitTest { namespace { @@ -239,5 +239,5 @@ namespace Juliet::UnitTest ArenaRelease(testArena); } -} // namespace Juliet::UnitTest +} // namespace UnitTest #endif diff --git a/Juliet/src/UnitTest/RunUnitTests.cpp b/Juliet/src/UnitTest/RunUnitTests.cpp index 504195d..d0db95d 100644 --- a/Juliet/src/UnitTest/RunUnitTests.cpp +++ b/Juliet/src/UnitTest/RunUnitTests.cpp @@ -1,11 +1,11 @@ -#include +#include #if JULIET_DEBUG #include #include -namespace Juliet::UnitTest +namespace UnitTest { // Forward declare the VectorUnitTest function void VectorUnitTest(); @@ -20,6 +20,6 @@ namespace Juliet::UnitTest LogMessage(LogCategory::Core, "Unit Tests Completed Successfully."); } -} // namespace Juliet::UnitTest +} // namespace UnitTest #endif diff --git a/JulietApp/main.cpp b/JulietApp/main.cpp index 677426e..d71adf9 100644 --- a/JulietApp/main.cpp +++ b/JulietApp/main.cpp @@ -1,4 +1,4 @@ -#include "main.h" +#include "main.h" #ifdef global #undef global @@ -53,7 +53,7 @@ static bool animateCamera = true; static bool freeCameraMode = false; static float camYaw = 0.0f; static float camPitch = 0.0f; -static Juliet::Vector3 camPos = { 25.0f, 0.0f, 12.5f }; +static Vector3 camPos = { 25.0f, 0.0f, 12.5f }; static float animateCubesTime = 0.0f; static float animateLightsTime = 0.0f; @@ -84,7 +84,6 @@ static float blueLightColor[3] = { 0.2f, 0.2f, 1.0f }; // TODO : Remove main.h. Useless // May be remove that Application class, useless too. -using namespace Juliet; namespace { @@ -505,7 +504,7 @@ void JulietApplication::Update(float deltaTime) // Memory debugger toggle static bool toggleDebounce = false; - if (IsKeyDown(Juliet::ScanCode::Home)) + if (IsKeyDown(ScanCode::Home)) { if (!toggleDebounce) { diff --git a/JulietApp/main.h b/JulietApp/main.h index a9cd095..4a90a73 100644 --- a/JulietApp/main.h +++ b/JulietApp/main.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -6,32 +6,29 @@ #include #include -namespace Juliet -{ - struct Mesh; - struct GraphicsTransferBuffer; - struct GraphicsBuffer; - struct GraphicsDevice; - struct Window; -} // namespace Juliet +struct Mesh; +struct GraphicsTransferBuffer; +struct GraphicsBuffer; +struct GraphicsDevice; +struct Window; -class JulietApplication : public Juliet::IApplication +class JulietApplication : public IApplication { protected: - void Init(Juliet::NonNullPtr arena) override; + void Init(NonNullPtr arena) override; void Shutdown() override; void Update(float deltaTime) override; bool IsRunning() override; - Juliet::Window* GetPlatformWindow() override { return MainWindow; } - Juliet::GraphicsDevice* GetGraphicsDevice() override { return GraphicsDevice; } + Window* GetPlatformWindow() override { return MainWindow; } + GraphicsDevice* GetGraphicsDevice() override { return GraphicsDevice; } // Render Lifecycle - Juliet::ColorTargetInfo GetColorTargetInfo(Juliet::Texture* swapchainTexture) override; - Juliet::DepthStencilTargetInfo* GetDepthTargetInfo() override; + ColorTargetInfo GetColorTargetInfo(Texture* swapchainTexture) override; + DepthStencilTargetInfo* GetDepthTargetInfo() override; #if 0 - Juliet::Camera GetDebugCamera() override; + Camera GetDebugCamera() override; #endif public: @@ -39,11 +36,11 @@ class JulietApplication : public Juliet::IApplication int GetAutoCloseFrameCount() const { return AutoCloseFrameCount; } private: - Juliet::Window* MainWindow = {}; - Juliet::GraphicsDevice* GraphicsDevice = {}; - Juliet::HotReloadCode GameCode = {}; - Juliet::GraphicsPipeline* GraphicsPipeline = {}; - Juliet::Texture* DepthBuffer = {}; + Window* MainWindow = {}; + GraphicsDevice* GraphicsDevice = {}; + HotReloadCode GameCode = {}; + GraphicsPipeline* GraphicsPipeline = {}; + Texture* DepthBuffer = {}; int AutoCloseFrameCount = -1; bool Running = false; diff --git a/JulietShaderCompiler/ShaderCompiler.cpp b/JulietShaderCompiler/ShaderCompiler.cpp index ae10fb8..177977a 100644 --- a/JulietShaderCompiler/ShaderCompiler.cpp +++ b/JulietShaderCompiler/ShaderCompiler.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -6,7 +6,6 @@ #include #include -using namespace Juliet; namespace { diff --git a/JulietShaderCompiler/ShaderCompiler.h b/JulietShaderCompiler/ShaderCompiler.h index 8a23b2c..9a68166 100644 --- a/JulietShaderCompiler/ShaderCompiler.h +++ b/JulietShaderCompiler/ShaderCompiler.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -29,8 +29,8 @@ enum class ShaderStage : uint8 struct ShaderInfo { ByteBuffer ByteCodeBuffer; - Juliet::String EntryPoint; - Juliet::String Name; + String EntryPoint; + String Name; ShaderStage Stage; }; diff --git a/JulietShaderCompiler/main.cpp b/JulietShaderCompiler/main.cpp index 09cd900..1f3049a 100644 --- a/JulietShaderCompiler/main.cpp +++ b/JulietShaderCompiler/main.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -6,7 +6,6 @@ #include #include -using namespace Juliet; void PrintHelp() { diff --git a/Romeo/src/AiGenerator.cpp b/Romeo/src/AiGenerator.cpp index ffbe4b3..441ddc0 100644 --- a/Romeo/src/AiGenerator.cpp +++ b/Romeo/src/AiGenerator.cpp @@ -10,7 +10,7 @@ namespace Romeo { - static Juliet::String ReadFileContent(Juliet::Arena* arena, const Juliet::String& path) + static String ReadFileContent(Arena* arena, const String& path) { Assert(arena != nullptr); if (path.Size == 0) @@ -20,7 +20,7 @@ namespace Romeo char pathBuf[512]; size_t copyLen = path.Size < 511 ? path.Size : 511; - memcpy(pathBuf, path.Data, copyLen); + memcpy(pathBuf, path.Str, copyLen); pathBuf[copyLen] = '\0'; FILE* f = nullptr; @@ -45,7 +45,7 @@ namespace Romeo size = 20480; } - char* buf = Juliet::ArenaPushArray(arena, static_cast(size + 1) JULIET_DEBUG_PARAM("FileReadContent")); + char* buf = ArenaPushArray(arena, static_cast(size + 1) JULIET_DEBUG_PARAM("FileReadContent")); size_t readBytes = fread(buf, 1, static_cast(size), f); buf[readBytes] = '\0'; @@ -53,7 +53,7 @@ namespace Romeo return { buf, readBytes }; } - static Juliet::String GetEnvironmentVar(Juliet::Arena* arena, const char* varName) + static String GetEnvironmentVar(Arena* arena, const char* varName) { Assert(arena != nullptr); Assert(varName != nullptr); @@ -64,7 +64,7 @@ namespace Romeo return {}; } - char* buf = Juliet::ArenaPushArray(arena, size JULIET_DEBUG_PARAM("EnvVar")); + char* buf = ArenaPushArray(arena, size JULIET_DEBUG_PARAM("EnvVar")); GetEnvironmentVariableA(varName, buf, size); return { buf, static_cast(size - 1) }; } @@ -72,13 +72,13 @@ namespace Romeo static bool G_OllamaReady = false; static bool PostWithRetry( - Juliet::Arena* arena, - const Juliet::String& host, + Arena* arena, + const String& host, int port, - const Juliet::String& path, + const String& path, bool isHttps, - const Juliet::String& requestBody, - Juliet::String& outResponse + const String& requestBody, + String& outResponse ) { if (isHttps) @@ -109,14 +109,14 @@ namespace Romeo return false; } - static bool PullOllamaModelIfNeeded(Juliet::Arena* arena, const Juliet::String& host, int port, const Juliet::String& modelName) + static bool PullOllamaModelIfNeeded(Arena* arena, const String& host, int port, const String& modelName) { size_t bodyCap = modelName.Size + 64; - char* showBodyBuf = Juliet::ArenaPushArray(arena, bodyCap JULIET_DEBUG_PARAM("ShowBody")); + char* showBodyBuf = ArenaPushArray(arena, bodyCap JULIET_DEBUG_PARAM("ShowBody")); int showLen = snprintf(showBodyBuf, bodyCap, "{\"name\":\"%.*s\"}", static_cast(modelName.Size), CStr(modelName)); - Juliet::String showBody = { showBodyBuf, static_cast(showLen > 0 ? showLen : 0) }; + String showBody = { showBodyBuf, static_cast(showLen > 0 ? showLen : 0) }; - Juliet::String showResponse = {}; + String showResponse = {}; bool showSuccess = PostWithRetry(arena, host, port, ConstString("/api/show"), false, showBody, showResponse); bool needsPull = false; @@ -129,7 +129,7 @@ namespace Romeo JsonValue root = {}; if (Json_Parse(arena, showResponse, root)) { - Juliet::String errorMsg = {}; + String errorMsg = {}; if (Json_Query(root, "error", errorMsg)) { needsPull = true; @@ -147,11 +147,11 @@ namespace Romeo static_cast(modelName.Size), CStr(modelName)); OutputDebugStringA("Romeo AI: Model not found. Pulling model...\n"); - char* pullBodyBuf = Juliet::ArenaPushArray(arena, bodyCap + 32 JULIET_DEBUG_PARAM("PullBody")); + char* pullBodyBuf = ArenaPushArray(arena, bodyCap + 32 JULIET_DEBUG_PARAM("PullBody")); int pullLen = snprintf(pullBodyBuf, bodyCap + 32, "{\"name\":\"%.*s\",\"stream\":false}", static_cast(modelName.Size), CStr(modelName)); - Juliet::String pullBody = { pullBodyBuf, static_cast(pullLen > 0 ? pullLen : 0) }; + String pullBody = { pullBodyBuf, static_cast(pullLen > 0 ? pullLen : 0) }; - Juliet::String pullResponse = {}; + String pullResponse = {}; bool pullSuccess = PostWithRetry(arena, host, port, ConstString("/api/pull"), false, pullBody, pullResponse); if (pullSuccess) { @@ -170,7 +170,7 @@ namespace Romeo return true; } - static Juliet::String CleanAndFormatDescription(Juliet::Arena* arena, const Juliet::String& rawResponse, bool enableCoT) + static String CleanAndFormatDescription(Arena* arena, const String& rawResponse, bool enableCoT) { Assert(arena != nullptr); if (rawResponse.Size == 0) @@ -184,8 +184,8 @@ namespace Romeo const char* thinkStart = strstr(pStr, ""); const char* thinkEnd = thinkStart ? strstr(thinkStart, "") : nullptr; - Juliet::String thinkContent = {}; - Juliet::String mainContent = {}; + String thinkContent = {}; + String mainContent = {}; if (thinkStart && thinkEnd && thinkEnd > thinkStart) { @@ -220,7 +220,7 @@ namespace Romeo if (enableCoT && thinkContent.Size > 0) { size_t resultCap = thinkContent.Size + mLen + 256; - char* resultBuf = Juliet::ArenaPushArray(arena, resultCap JULIET_DEBUG_PARAM("CoTFormattedDesc")); + char* resultBuf = ArenaPushArray(arena, resultCap JULIET_DEBUG_PARAM("CoTFormattedDesc")); int written = snprintf(resultBuf, resultCap, "
\nChain of Thought\n\n%.*s\n\n
\n\n%.*s", static_cast(thinkContent.Size), CStr(thinkContent), @@ -229,30 +229,30 @@ namespace Romeo return { resultBuf, static_cast(written > 0 ? written : 0) }; } - char* resultBuf = Juliet::ArenaPushArray(arena, mLen + 1 JULIET_DEBUG_PARAM("CleanedDesc")); + char* resultBuf = ArenaPushArray(arena, mLen + 1 JULIET_DEBUG_PARAM("CleanedDesc")); memcpy(resultBuf, mPtr, mLen); resultBuf[mLen] = '\0'; return { resultBuf, mLen }; } bool AI_GenerateDescription( - Juliet::Arena* arena, + Arena* arena, FileEntry& entry ) { Assert(arena != nullptr); - Juliet::String headerContent = ReadFileContent(arena, entry.HeaderPath); - Juliet::String cppContent = ReadFileContent(arena, entry.CppPath); + String headerContent = ReadFileContent(arena, entry.HeaderPath); + String cppContent = ReadFileContent(arena, entry.CppPath); if (headerContent.Size == 0 && cppContent.Size == 0) { - entry.Description = Juliet::StringCopy(arena, ConstString("*File is empty.*")); + entry.Description = StringCopy(arena, ConstString("*File is empty.*")); return true; } - Juliet::String cotEnv = GetEnvironmentVar(arena, "ROMEO_ENABLE_COT"); - bool enableCoT = (cotEnv.Size > 0 && (cotEnv.Data[0] == '1' || cotEnv.Data[0] == 't' || cotEnv.Data[0] == 'T' || cotEnv.Data[0] == 'y' || cotEnv.Data[0] == 'Y')); + String cotEnv = GetEnvironmentVar(arena, "ROMEO_ENABLE_COT"); + bool enableCoT = (cotEnv.Size > 0 && (cotEnv.Str[0] == '1' || cotEnv.Str[0] == 't' || cotEnv.Str[0] == 'T' || cotEnv.Str[0] == 'y' || cotEnv.Str[0] == 'Y')); const char* sysPromptNoCoT = "You are a technical documentation assistant. Provide a single, concise, unified paragraph overview (50-80 words) describing the main purpose and design of this C++ component.\n" "Rules:\n" @@ -270,7 +270,7 @@ namespace Romeo const char* sysPrompt = enableCoT ? sysPromptCoT : sysPromptNoCoT; size_t promptCap = strlen(sysPrompt) + entry.HeaderPath.Size + headerContent.Size + entry.CppPath.Size + cppContent.Size + entry.Description.Size + 512; - char* promptBuf = Juliet::ArenaPushArray(arena, promptCap JULIET_DEBUG_PARAM("PromptBuf")); + char* promptBuf = ArenaPushArray(arena, promptCap JULIET_DEBUG_PARAM("PromptBuf")); int written = 0; if (entry.Description.Size > 0) @@ -306,12 +306,12 @@ namespace Romeo ); } - Juliet::String prompt = { promptBuf, static_cast(written > 0 ? written : 0) }; - Juliet::String escapedPrompt = Json_EscapeString(arena, prompt); + String prompt = { promptBuf, static_cast(written > 0 ? written : 0) }; + String escapedPrompt = Json_EscapeString(arena, prompt); - Juliet::String host = ConstString("127.0.0.1"); + String host = ConstString("127.0.0.1"); int port = 11434; - Juliet::String modelName = GetEnvironmentVar(arena, "ROMEO_LLM_MODEL"); + String modelName = GetEnvironmentVar(arena, "ROMEO_LLM_MODEL"); if (modelName.Size == 0) { modelName = ConstString("qwen2.5-coder:1.5b"); @@ -330,16 +330,16 @@ namespace Romeo int maxPredictTokens = enableCoT ? 600 : 300; size_t bodyCap = modelName.Size + escapedPrompt.Size + 512; - char* bodyBuf = Juliet::ArenaPushArray(arena, bodyCap JULIET_DEBUG_PARAM("OllamaBody")); + char* bodyBuf = ArenaPushArray(arena, bodyCap JULIET_DEBUG_PARAM("OllamaBody")); int bodyLen = snprintf(bodyBuf, bodyCap, "{\"model\":\"%.*s\",\"prompt\":\"%.*s\",\"stream\":false,\"options\":{\"temperature\":0.2,\"num_predict\":%d}}", static_cast(modelName.Size), CStr(modelName), static_cast(escapedPrompt.Size), CStr(escapedPrompt), maxPredictTokens ); - Juliet::String body = { bodyBuf, static_cast(bodyLen > 0 ? bodyLen : 0) }; + String body = { bodyBuf, static_cast(bodyLen > 0 ? bodyLen : 0) }; - Juliet::String response = {}; + String response = {}; bool success = PostWithRetry( arena, host, @@ -355,7 +355,7 @@ namespace Romeo JsonValue root = {}; if (Json_Parse(arena, response, root)) { - Juliet::String desc = {}; + String desc = {}; if (Json_Query(root, "response", desc)) { entry.Description = CleanAndFormatDescription(arena, desc, enableCoT); diff --git a/Romeo/src/AiGenerator.h b/Romeo/src/AiGenerator.h index 1899747..2b41e0d 100644 --- a/Romeo/src/AiGenerator.h +++ b/Romeo/src/AiGenerator.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include "Database.h" @@ -8,7 +8,7 @@ namespace Romeo // Generates a description for the file entry using local Ollama or cloud Gemini API. // Returns true if generation was successful and entry.Description was populated. [[nodiscard]] bool AI_GenerateDescription( - Juliet::Arena* arena, + Arena* arena, FileEntry& entry ); } diff --git a/Romeo/src/Database.cpp b/Romeo/src/Database.cpp index 49bcbc3..3e77d1e 100644 --- a/Romeo/src/Database.cpp +++ b/Romeo/src/Database.cpp @@ -6,7 +6,7 @@ namespace Romeo { - void DB_Init(Database& db, Juliet::Arena* arena) + void DB_Init(Database& db, Arena* arena) { printf("Entering DB_Init...\n"); db.DbArena = arena; @@ -17,10 +17,10 @@ namespace Romeo struct ScanContext { Database* Db; - Juliet::Arena* TempArena; + Arena* TempArena; }; - static void ProcessFile(ScanContext& ctx, const Juliet::String& path, const WIN32_FIND_DATAW& findData) + static void ProcessFile(ScanContext& ctx, const String& path, const WIN32_FIND_DATAW& findData) { // Simple filter: only .h and .cpp const char* pPath = CStr(path); @@ -67,7 +67,7 @@ namespace Romeo FileEntry* entry = nullptr; for (FileEntry& e : ctx.Db->Entries) { - Juliet::String dbPath = e.HeaderPath.Size > 0 ? e.HeaderPath : e.CppPath; + String dbPath = e.HeaderPath.Size > 0 ? e.HeaderPath : e.CppPath; if (dbPath.Size > 0) { const char* pDbPath = CStr(dbPath); @@ -102,22 +102,22 @@ namespace Romeo if (isHeader) { - entry->HeaderPath = Juliet::StringCopy(ctx.Db->DbArena, path); + entry->HeaderPath = StringCopy(ctx.Db->DbArena, path); entry->LastModifiedHeader = lastModified; } else { - entry->CppPath = Juliet::StringCopy(ctx.Db->DbArena, path); + entry->CppPath = StringCopy(ctx.Db->DbArena, path); entry->LastModifiedCpp = lastModified; } } - static void ScanDirectoryRecursive(ScanContext& ctx, const Juliet::String& currentDir) + static void ScanDirectoryRecursive(ScanContext& ctx, const String& currentDir) { size_t searchPathLen = currentDir.Size + 3; // "\*" + null char* searchPathBuf = ArenaPushArray(ctx.TempArena, searchPathLen JULIET_DEBUG_PARAM("RomeoDbSearchPathBuf")); snprintf(searchPathBuf, searchPathLen, "%s\\*", CStr(currentDir)); - Juliet::String searchPath = {searchPathBuf, searchPathLen - 1}; + String searchPath = {searchPathBuf, searchPathLen - 1}; // Convert to wide string for Win32 int wLen = MultiByteToWideChar(CP_UTF8, 0, CStr(searchPath), -1, nullptr, 0); @@ -152,7 +152,7 @@ namespace Romeo size_t fullPathLen = currentDir.Size + 1 + static_cast(uLen); // "\" + null char* fullPathBuf = ArenaPushArray(ctx.TempArena, fullPathLen JULIET_DEBUG_PARAM("RomeoDbFullPathBuf")); snprintf(fullPathBuf, fullPathLen, "%s\\%s", CStr(currentDir), uFileName); - Juliet::String fullPath = {fullPathBuf, fullPathLen - 1}; + String fullPath = {fullPathBuf, fullPathLen - 1}; if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { @@ -171,7 +171,7 @@ namespace Romeo FindClose(hFind); } - void DB_ScanWorkspace(Database& db, Juliet::Arena* tempArena, const Juliet::String& rootDir) + void DB_ScanWorkspace(Database& db, Arena* tempArena, const String& rootDir) { Assert(tempArena != nullptr); ScanContext ctx; @@ -186,7 +186,7 @@ namespace Romeo { snprintf(srcDirBuf, sizeof(srcDirBuf), "%s\\Juliet\\src", CStr(rootDir)); } - Juliet::String srcDir = Juliet::StringCopy(tempArena, Juliet::WrapString(srcDirBuf)); + String srcDir = StringCopy(tempArena, WrapString(srcDirBuf)); char incDirBuf[512]; snprintf(incDirBuf, sizeof(incDirBuf), "%s\\include", CStr(rootDir)); @@ -195,13 +195,13 @@ namespace Romeo { snprintf(incDirBuf, sizeof(incDirBuf), "%s\\Juliet\\include", CStr(rootDir)); } - Juliet::String incDir = Juliet::StringCopy(tempArena, Juliet::WrapString(incDirBuf)); + String incDir = StringCopy(tempArena, WrapString(incDirBuf)); ScanDirectoryRecursive(ctx, srcDir); ScanDirectoryRecursive(ctx, incDir); } - bool DB_Save(const Database& db, const Juliet::String& filePath) + bool DB_Save(const Database& db, const String& filePath) { FILE* file = nullptr; if (fopen_s(&file, CStr(filePath), "wb") != 0 || !file) @@ -216,11 +216,11 @@ namespace Romeo { uint64_t hLen = entry.HeaderPath.Size; fwrite(&hLen, sizeof(uint64_t), 1, file); - if (hLen > 0) fwrite(entry.HeaderPath.Data, 1, static_cast(hLen), file); + if (hLen > 0) fwrite(entry.HeaderPath.Str, 1, static_cast(hLen), file); uint64_t cLen = entry.CppPath.Size; fwrite(&cLen, sizeof(uint64_t), 1, file); - if (cLen > 0) fwrite(entry.CppPath.Data, 1, static_cast(cLen), file); + if (cLen > 0) fwrite(entry.CppPath.Str, 1, static_cast(cLen), file); fwrite(&entry.LastModifiedHeader, sizeof(uint64_t), 1, file); fwrite(&entry.LastModifiedCpp, sizeof(uint64_t), 1, file); @@ -229,14 +229,14 @@ namespace Romeo uint64_t dLen = entry.Description.Size; fwrite(&dLen, sizeof(uint64_t), 1, file); - if (dLen > 0) fwrite(entry.Description.Data, 1, static_cast(dLen), file); + if (dLen > 0) fwrite(entry.Description.Str, 1, static_cast(dLen), file); } fclose(file); return true; } - bool DB_Load(Database& db, const Juliet::String& filePath) + bool DB_Load(Database& db, const String& filePath) { FILE* file = nullptr; if (fopen_s(&file, CStr(filePath), "rb") != 0 || !file) @@ -261,20 +261,20 @@ namespace Romeo if (fread(&hLen, sizeof(uint64_t), 1, file) != 1) break; if (hLen > 0) { - entry.HeaderPath.Data = ArenaPushArray(db.DbArena, static_cast(hLen + 1) JULIET_DEBUG_PARAM("DbLoadHeader")); + entry.HeaderPath.Str = ArenaPushArray(db.DbArena, static_cast(hLen + 1) JULIET_DEBUG_PARAM("DbLoadHeader")); entry.HeaderPath.Size = static_cast(hLen); - fread(entry.HeaderPath.Data, 1, static_cast(hLen), file); - entry.HeaderPath.Data[hLen] = '\0'; + fread(entry.HeaderPath.Str, 1, static_cast(hLen), file); + entry.HeaderPath.Str[hLen] = '\0'; } uint64_t cLen = 0; if (fread(&cLen, sizeof(uint64_t), 1, file) != 1) break; if (cLen > 0) { - entry.CppPath.Data = ArenaPushArray(db.DbArena, static_cast(cLen + 1) JULIET_DEBUG_PARAM("DbLoadCpp")); + entry.CppPath.Str = ArenaPushArray(db.DbArena, static_cast(cLen + 1) JULIET_DEBUG_PARAM("DbLoadCpp")); entry.CppPath.Size = static_cast(cLen); - fread(entry.CppPath.Data, 1, static_cast(cLen), file); - entry.CppPath.Data[cLen] = '\0'; + fread(entry.CppPath.Str, 1, static_cast(cLen), file); + entry.CppPath.Str[cLen] = '\0'; } fread(&entry.LastModifiedHeader, sizeof(uint64_t), 1, file); @@ -286,10 +286,10 @@ namespace Romeo if (fread(&dLen, sizeof(uint64_t), 1, file) != 1) break; if (dLen > 0) { - entry.Description.Data = ArenaPushArray(db.DbArena, static_cast(dLen + 1) JULIET_DEBUG_PARAM("DbLoadDesc")); + entry.Description.Str = ArenaPushArray(db.DbArena, static_cast(dLen + 1) JULIET_DEBUG_PARAM("DbLoadDesc")); entry.Description.Size = static_cast(dLen); - fread(entry.Description.Data, 1, static_cast(dLen), file); - entry.Description.Data[dLen] = '\0'; + fread(entry.Description.Str, 1, static_cast(dLen), file); + entry.Description.Str[dLen] = '\0'; } db.Entries.PushBack(entry); diff --git a/Romeo/src/Database.h b/Romeo/src/Database.h index b5dc292..65463f0 100644 --- a/Romeo/src/Database.h +++ b/Romeo/src/Database.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -10,8 +10,8 @@ namespace Romeo { struct FileEntry { - Juliet::String HeaderPath; - Juliet::String CppPath; + String HeaderPath; + String CppPath; // Stored as Windows FILETIME (uint64_t) for easy comparison uint64_t LastModifiedHeader = 0; @@ -20,24 +20,24 @@ namespace Romeo uint64_t LastMarkdownCreatedTime = 0; uint64_t LastAIGeneratedTime = 0; - Juliet::String Description; + String Description; }; struct Database { - Juliet::VectorArena Entries = {}; - Juliet::Arena* DbArena = nullptr; - Juliet::Mutex Mutex; + VectorArena Entries = {}; + Arena* DbArena = nullptr; + Mutex Mutex; }; // Initialize the DB using the provided memory arena - void DB_Init(Database& db, Juliet::Arena* arena); + void DB_Init(Database& db, Arena* arena); // Scan a workspace directory for pairs of .h/.cpp and update the database structure. - void DB_ScanWorkspace(Database& db, Juliet::Arena* tempArena, const Juliet::String& rootDir); + void DB_ScanWorkspace(Database& db, Arena* tempArena, const String& rootDir); // Save and load DB state from disk (e.g. Romeo/docs/romeo_db.json or .bin) - bool DB_Save(const Database& db, const Juliet::String& filePath); - bool DB_Load(Database& db, const Juliet::String& filePath); + bool DB_Save(const Database& db, const String& filePath); + bool DB_Load(Database& db, const String& filePath); } // namespace Romeo diff --git a/Romeo/src/HttpClient.cpp b/Romeo/src/HttpClient.cpp index 46c3a51..22b7470 100644 --- a/Romeo/src/HttpClient.cpp +++ b/Romeo/src/HttpClient.cpp @@ -6,7 +6,7 @@ namespace Romeo { - static wchar_t* ConvertToWide(Juliet::Arena* arena, const Juliet::String& str) + static wchar_t* ConvertToWide(Arena* arena, const String& str) { Assert(arena != nullptr); if (str.Size == 0) @@ -18,20 +18,20 @@ namespace Romeo { return const_cast(L""); } - wchar_t* wBuf = Juliet::ArenaPushArray(arena, static_cast(wLen + 1) JULIET_DEBUG_PARAM("WideStr")); + wchar_t* wBuf = ArenaPushArray(arena, static_cast(wLen + 1) JULIET_DEBUG_PARAM("WideStr")); MultiByteToWideChar(CP_UTF8, 0, CStr(str), static_cast(str.Size), wBuf, wLen); wBuf[wLen] = L'\0'; return wBuf; } bool HttpClient::Post( - Juliet::Arena* arena, - const Juliet::String& host, + Arena* arena, + const String& host, int port, - const Juliet::String& path, + const String& path, bool isHttps, - const Juliet::String& requestBody, - Juliet::String& outResponse + const String& requestBody, + String& outResponse ) { Assert(arena != nullptr); @@ -101,7 +101,7 @@ namespace Romeo size_t totalBytes = 0; size_t capacity = 1024; - char* responseData = Juliet::ArenaPushArray(arena, capacity JULIET_DEBUG_PARAM("HttpResponse")); + char* responseData = ArenaPushArray(arena, capacity JULIET_DEBUG_PARAM("HttpResponse")); do { @@ -124,7 +124,7 @@ namespace Romeo newCapacity = totalBytes + dwSize + 1; } - char* newBuf = Juliet::ArenaPushArray(arena, newCapacity JULIET_DEBUG_PARAM("HttpResponseGrow")); + char* newBuf = ArenaPushArray(arena, newCapacity JULIET_DEBUG_PARAM("HttpResponseGrow")); memcpy(newBuf, responseData, totalBytes); responseData = newBuf; capacity = newCapacity; @@ -157,7 +157,7 @@ namespace Romeo if (totalBytes > 0) { responseData[totalBytes] = '\0'; - outResponse.Data = responseData; + outResponse.Str = responseData; outResponse.Size = totalBytes; success = true; } diff --git a/Romeo/src/HttpClient.h b/Romeo/src/HttpClient.h index f9c1e68..6fcd6bb 100644 --- a/Romeo/src/HttpClient.h +++ b/Romeo/src/HttpClient.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include @@ -10,13 +10,13 @@ namespace Romeo // Sends a POST request over HTTP/HTTPS. // Response data is allocated on the provided arena and returned in outResponse. [[nodiscard]] static bool Post( - Juliet::Arena* arena, - const Juliet::String& host, + Arena* arena, + const String& host, int port, - const Juliet::String& path, + const String& path, bool isHttps, - const Juliet::String& requestBody, - Juliet::String& outResponse + const String& requestBody, + String& outResponse ); }; } diff --git a/Romeo/src/JsonParser.cpp b/Romeo/src/JsonParser.cpp index 74a9d47..1c0b879 100644 --- a/Romeo/src/JsonParser.cpp +++ b/Romeo/src/JsonParser.cpp @@ -9,7 +9,7 @@ namespace Romeo { struct JsonParserState { - Juliet::Arena* Arena; + Arena* Arena; const char* Ptr; const char* End; }; @@ -30,7 +30,7 @@ namespace Romeo } } - static bool ParseString(JsonParserState& state, Juliet::String& outStr) + static bool ParseString(JsonParserState& state, String& outStr) { if (state.Ptr >= state.End || *state.Ptr != '"') { @@ -69,7 +69,7 @@ namespace Romeo const char* endQuote = state.Ptr; state.Ptr++; - char* buf = Juliet::ArenaPushArray(state.Arena, len + 1 JULIET_DEBUG_PARAM("JsonParsedStr")); + char* buf = ArenaPushArray(state.Arena, len + 1 JULIET_DEBUG_PARAM("JsonParsedStr")); if (hasEscape) { @@ -114,14 +114,14 @@ namespace Romeo readPtr++; } buf[writeIdx] = '\0'; - outStr.Data = buf; + outStr.Str = buf; outStr.Size = writeIdx; } else { memcpy(buf, start, len); buf[len] = '\0'; - outStr.Data = buf; + outStr.Str = buf; outStr.Size = len; } @@ -149,7 +149,7 @@ namespace Romeo return true; } - Juliet::String key = {}; + String key = {}; if (!ParseString(state, key)) { return false; @@ -164,7 +164,7 @@ namespace Romeo JsonKeyValue kv = {}; kv.Key = key; - kv.Value = Juliet::ArenaPushArray(state.Arena, 1 JULIET_DEBUG_PARAM("JsonValueRef")); + kv.Value = ArenaPushArray(state.Arena, 1 JULIET_DEBUG_PARAM("JsonValueRef")); new (kv.Value) JsonValue(); if (!ParseValue(state, *kv.Value)) @@ -334,7 +334,7 @@ namespace Romeo return false; } - bool Json_Parse(Juliet::Arena* arena, const Juliet::String& jsonStr, JsonValue& outValue) + bool Json_Parse(Arena* arena, const String& jsonStr, JsonValue& outValue) { Assert(arena != nullptr); if (jsonStr.Size == 0) @@ -350,7 +350,7 @@ namespace Romeo return ParseValue(state, outValue); } - bool Json_Query(const JsonValue& root, const char* path, Juliet::String& outResult) + bool Json_Query(const JsonValue& root, const char* path, String& outResult) { Assert(path != nullptr); @@ -425,7 +425,7 @@ namespace Romeo return false; } - Juliet::String Json_EscapeString(Juliet::Arena* arena, const Juliet::String& str) + String Json_EscapeString(Arena* arena, const String& str) { Assert(arena != nullptr); @@ -450,7 +450,7 @@ namespace Romeo p++; } - char* buf = Juliet::ArenaPushArray(arena, escLen + 1 JULIET_DEBUG_PARAM("JsonEscapedStr")); + char* buf = ArenaPushArray(arena, escLen + 1 JULIET_DEBUG_PARAM("JsonEscapedStr")); char* dst = buf; p = reinterpret_cast(CStr(str)); while (p < end) diff --git a/Romeo/src/JsonParser.h b/Romeo/src/JsonParser.h index d87a23e..5c1fbb5 100644 --- a/Romeo/src/JsonParser.h +++ b/Romeo/src/JsonParser.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -19,7 +19,7 @@ namespace Romeo struct JsonKeyValue { - Juliet::String Key; + String Key; // Pointer is used here since JsonValue contains JsonKeyValue, forming mutual dependency JsonValue* Value = nullptr; }; @@ -29,18 +29,18 @@ namespace Romeo JsonType Type = JsonType::Null; bool BoolVal = false; double NumVal = 0.0; - Juliet::String StrVal = {}; + String StrVal = {}; - Juliet::VectorArena ArrayVal = {}; - Juliet::VectorArena ObjectVal = {}; + VectorArena ArrayVal = {}; + VectorArena ObjectVal = {}; }; // Parses a JSON string. Memory is allocated on the provided arena. - [[nodiscard]] bool Json_Parse(Juliet::Arena* arena, const Juliet::String& jsonStr, JsonValue& outValue); + [[nodiscard]] bool Json_Parse(Arena* arena, const String& jsonStr, JsonValue& outValue); // Queries a nested string value by path (e.g., "candidates/0/content/parts/0/text" or "response"). - [[nodiscard]] bool Json_Query(const JsonValue& root, const char* path, Juliet::String& outResult); + [[nodiscard]] bool Json_Query(const JsonValue& root, const char* path, String& outResult); // Escapes a string to be safely embedded inside JSON. - [[nodiscard]] Juliet::String Json_EscapeString(Juliet::Arena* arena, const Juliet::String& str); + [[nodiscard]] String Json_EscapeString(Arena* arena, const String& str); } diff --git a/Romeo/src/MarkdownGenerator.cpp b/Romeo/src/MarkdownGenerator.cpp index c341ec2..1f3bf24 100644 --- a/Romeo/src/MarkdownGenerator.cpp +++ b/Romeo/src/MarkdownGenerator.cpp @@ -12,12 +12,12 @@ namespace Romeo { struct ParsedSymbol { - Juliet::String Name; - Juliet::String ReturnType; - Juliet::String Parameters; - Juliet::String Type; // "class", "struct", "union", "enum", "enum class", "function" - Juliet::String Namespace; - Juliet::String ClassContext; + String Name; + String ReturnType; + String Parameters; + String Type; // "class", "struct", "union", "enum", "enum class", "function" + String Namespace; + String ClassContext; bool IsConst = false; }; @@ -35,7 +35,7 @@ namespace Romeo struct StringBuilder { - Juliet::Arena* Arena; + Arena* Arena; char* Buffer = nullptr; size_t Size = 0; size_t Capacity = 0; @@ -62,7 +62,7 @@ namespace Romeo { newCap *= 2; } - char* newBuf = Juliet::ArenaPushArray(Arena, newCap JULIET_DEBUG_PARAM("StringBuilder")); + char* newBuf = ArenaPushArray(Arena, newCap JULIET_DEBUG_PARAM("StringBuilder")); if (Buffer) { memcpy(newBuf, Buffer, Size); @@ -82,7 +82,7 @@ namespace Romeo #endif }; - static Juliet::String ReadFileContent(Juliet::Arena* arena, const char* pathBuf) + static String ReadFileContent(Arena* arena, const char* pathBuf) { FILE* f = nullptr; if (fopen_s(&f, pathBuf, "rb") != 0 || !f) @@ -100,7 +100,7 @@ namespace Romeo return {}; } - char* buf = Juliet::ArenaPushArray(arena, static_cast(size + 1) JULIET_DEBUG_PARAM("FileReadContent")); + char* buf = ArenaPushArray(arena, static_cast(size + 1) JULIET_DEBUG_PARAM("FileReadContent")); size_t readBytes = fread(buf, 1, static_cast(size), f); buf[readBytes] = '\0'; @@ -108,7 +108,7 @@ namespace Romeo return { buf, readBytes }; } - static Juliet::String GetRelativeString(const Juliet::String& absolutePath, const Juliet::String& workspaceRoot) + static String GetRelativeString(const String& absolutePath, const String& workspaceRoot) { if (absolutePath.Size > workspaceRoot.Size) { @@ -151,9 +151,9 @@ namespace Romeo return absolutePath; } - static Juliet::String BuildMarkdownFileName(Juliet::Arena* arena, const char* relativeBaseName, size_t baseLen) + static String BuildMarkdownFileName(Arena* arena, const char* relativeBaseName, size_t baseLen) { - char* buf = Juliet::ArenaPushArray(arena, baseLen + 4 JULIET_DEBUG_PARAM("MdFileName")); + char* buf = ArenaPushArray(arena, baseLen + 4 JULIET_DEBUG_PARAM("MdFileName")); for (size_t i = 0; i < baseLen; ++i) { char c = relativeBaseName[i]; @@ -170,7 +170,7 @@ namespace Romeo return {buf, baseLen + 3}; } - static Juliet::String Trim(const char* start, const char* end) + static String Trim(const char* start, const char* end) { if (end < start) { @@ -412,16 +412,16 @@ namespace Romeo } static void ParseSymbolsFromFile( - Juliet::Arena* arena, - const Juliet::String& filePath, - Juliet::VectorArena& outSymbols + Arena* arena, + const String& filePath, + VectorArena& outSymbols ) { Assert(arena != nullptr); char pathBuf[512]; size_t copyLen = filePath.Size < 511 ? filePath.Size : 511; - memcpy(pathBuf, filePath.Data, copyLen); + memcpy(pathBuf, filePath.Str, copyLen); pathBuf[copyLen] = '\0'; FILE* srcFile = nullptr; @@ -437,7 +437,7 @@ namespace Romeo return; } - char* buffer = Juliet::ArenaPushArray(arena, static_cast(fileSize) + 1 JULIET_DEBUG_PARAM("SourceFileBuffer")); + char* buffer = ArenaPushArray(arena, static_cast(fileSize) + 1 JULIET_DEBUG_PARAM("SourceFileBuffer")); size_t readBytes = fread(buffer, 1, static_cast(fileSize), srcFile); buffer[readBytes] = '\0'; fclose(srcFile); @@ -555,7 +555,7 @@ namespace Romeo if (nameT.Length > 0 && nameT.IsIdentifier) { ParsedSymbol sym = {}; - sym.Name = Juliet::StringCopy(arena, { const_cast(nameT.Start), nameT.Length }); + sym.Name = StringCopy(arena, { const_cast(nameT.Start), nameT.Length }); if (isEnumClass) { sym.Type = ConstString("enum class"); @@ -567,11 +567,11 @@ namespace Romeo char nsBuf[128]; GetCurrentNamespace(nsBuf, sizeof(nsBuf), namespaceStack, namespaceStackCount); - sym.Namespace = Juliet::StringCopy(arena, Juliet::WrapString(nsBuf)); + sym.Namespace = StringCopy(arena, WrapString(nsBuf)); char clBuf[128]; GetCurrentClassContext(clBuf, sizeof(clBuf), classStack, classStackCount); - sym.ClassContext = Juliet::StringCopy(arena, Juliet::WrapString(clBuf)); + sym.ClassContext = StringCopy(arena, WrapString(clBuf)); outSymbols.PushBack(sym); } @@ -613,17 +613,17 @@ namespace Romeo // Also store the class itself as a symbol! ParsedSymbol classSym = {}; - classSym.Name = Juliet::StringCopy(arena, Juliet::WrapString(classStack[classStackCount-1].Name)); - classSym.Type = Juliet::StringCopy(arena, Juliet::WrapString(pendingClassType)); + classSym.Name = StringCopy(arena, WrapString(classStack[classStackCount-1].Name)); + classSym.Type = StringCopy(arena, WrapString(pendingClassType)); char nsBuf[128]; GetCurrentNamespace(nsBuf, sizeof(nsBuf), namespaceStack, namespaceStackCount); - classSym.Namespace = Juliet::StringCopy(arena, Juliet::WrapString(nsBuf)); + classSym.Namespace = StringCopy(arena, WrapString(nsBuf)); char clBuf[128]; // Get class context *excluding* the one we just pushed GetCurrentClassContext(clBuf, sizeof(clBuf), classStack, classStackCount - 1); - classSym.ClassContext = Juliet::StringCopy(arena, Juliet::WrapString(clBuf)); + classSym.ClassContext = StringCopy(arena, WrapString(clBuf)); outSymbols.PushBack(classSym); @@ -678,8 +678,8 @@ namespace Romeo bool isConst = false; if (matchingParen != nullptr && IsFunctionFollowup(matchingParen, end, opensBody, isConst)) { - Juliet::String returnTypeRaw = Trim(lastStatementEnd, funcNameT.Start); - Juliet::String paramsRaw = Trim(t.Start + 1, matchingParen - 1); + String returnTypeRaw = Trim(lastStatementEnd, funcNameT.Start); + String paramsRaw = Trim(t.Start + 1, matchingParen - 1); char activeClass[128] = ""; GetCurrentClassContext(activeClass, sizeof(activeClass), classStack, classStackCount); @@ -706,17 +706,17 @@ namespace Romeo if (hasReturnType || isConstructorOrDestructor) { ParsedSymbol funcSym = {}; - funcSym.Name = Juliet::StringCopy(arena, { const_cast(funcNameT.Start), funcNameT.Length }); - funcSym.ReturnType = Juliet::StringCopy(arena, returnTypeRaw); - funcSym.Parameters = Juliet::StringCopy(arena, paramsRaw); + funcSym.Name = StringCopy(arena, { const_cast(funcNameT.Start), funcNameT.Length }); + funcSym.ReturnType = StringCopy(arena, returnTypeRaw); + funcSym.Parameters = StringCopy(arena, paramsRaw); funcSym.Type = ConstString("function"); funcSym.IsConst = isConst; char nsBuf[128]; GetCurrentNamespace(nsBuf, sizeof(nsBuf), namespaceStack, namespaceStackCount); - funcSym.Namespace = Juliet::StringCopy(arena, Juliet::WrapString(nsBuf)); + funcSym.Namespace = StringCopy(arena, WrapString(nsBuf)); - funcSym.ClassContext = Juliet::StringCopy(arena, Juliet::WrapString(activeClass)); + funcSym.ClassContext = StringCopy(arena, WrapString(activeClass)); outSymbols.PushBack(funcSym); } @@ -727,10 +727,10 @@ namespace Romeo } } - static void FormatAndWriteSymbols(StringBuilder& sb, Juliet::Arena* arena, const Juliet::String& filePath) + static void FormatAndWriteSymbols(StringBuilder& sb, Arena* arena, const String& filePath) { printf("Romeo: FormatAndWriteSymbols start for %.*s\n", static_cast(filePath.Size), CStr(filePath)); - Juliet::VectorArena symbols = {}; + VectorArena symbols = {}; symbols.Create(arena JULIET_DEBUG_ONLY(, "ParsedSymbols")); printf("Romeo: Calling ParseSymbolsFromFile...\n"); @@ -745,15 +745,15 @@ namespace Romeo // Collect all distinct namespaces printf("Romeo: Collecting namespaces...\n"); - Juliet::VectorArena namespaces = {}; + VectorArena namespaces = {}; namespaces.Create(arena JULIET_DEBUG_ONLY(, "NamespacesList")); for (const ParsedSymbol& sym : symbols) { bool found = false; - for (const Juliet::String& ns : namespaces) + for (const String& ns : namespaces) { - if (Juliet::StringCompare(ns, sym.Namespace) == 0) + if (StringCompare(ns, sym.Namespace) == 0) { found = true; break; @@ -766,7 +766,7 @@ namespace Romeo } printf("Romeo: Namespace collection done.\n"); - for (const Juliet::String& ns : namespaces) + for (const String& ns : namespaces) { printf("Romeo: Formatting namespace %.*s...\n", static_cast(ns.Size), CStr(ns)); if (ns.Size > 0) @@ -782,10 +782,10 @@ namespace Romeo bool hasTypes = false; for (const ParsedSymbol& sym : symbols) { - if (Juliet::StringCompare(sym.Namespace, ns) == 0 && - (Juliet::StringCompare(sym.Type, ConstString("class")) == 0 || - Juliet::StringCompare(sym.Type, ConstString("struct")) == 0 || - Juliet::StringCompare(sym.Type, ConstString("union")) == 0)) + if (StringCompare(sym.Namespace, ns) == 0 && + (StringCompare(sym.Type, ConstString("class")) == 0 || + StringCompare(sym.Type, ConstString("struct")) == 0 || + StringCompare(sym.Type, ConstString("union")) == 0)) { if (!hasTypes) { @@ -813,9 +813,9 @@ namespace Romeo bool hasEnums = false; for (const ParsedSymbol& sym : symbols) { - if (Juliet::StringCompare(sym.Namespace, ns) == 0 && - (Juliet::StringCompare(sym.Type, ConstString("enum")) == 0 || - Juliet::StringCompare(sym.Type, ConstString("enum class")) == 0)) + if (StringCompare(sym.Namespace, ns) == 0 && + (StringCompare(sym.Type, ConstString("enum")) == 0 || + StringCompare(sym.Type, ConstString("enum class")) == 0)) { if (!hasEnums) { @@ -843,8 +843,8 @@ namespace Romeo bool hasFuncs = false; for (const ParsedSymbol& sym : symbols) { - if (Juliet::StringCompare(sym.Namespace, ns) == 0 && - Juliet::StringCompare(sym.Type, ConstString("function")) == 0) + if (StringCompare(sym.Namespace, ns) == 0 && + StringCompare(sym.Type, ConstString("function")) == 0) { if (!hasFuncs) { @@ -871,7 +871,7 @@ namespace Romeo } } - void MD_GenerateDocumentation(Database& db, const Juliet::String& workspaceRoot, const Juliet::String& docsDir) + void MD_GenerateDocumentation(Database& db, const String& workspaceRoot, const String& docsDir) { EnsureDirectoryExists(CStr(docsDir)); @@ -912,13 +912,13 @@ namespace Romeo uint64_t currentTime = (static_cast(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; // Temporary arena for parsing symbols and formatting - Juliet::ArenaParams params{}; - Juliet::Arena* tempArena = Juliet::ArenaAllocate(params JULIET_DEBUG_PARAM("MdGeneratorTempArena")); + ArenaParams params{}; + Arena* tempArena = ArenaAllocate(params); Assert(tempArena != nullptr); // Separate arena for AI generation (gets cleared after each file to prevent exhaustion) - Juliet::ArenaParams aiParams{}; - Juliet::Arena* aiArena = Juliet::ArenaAllocate(aiParams JULIET_DEBUG_PARAM("AiGeneratorArena")); + ArenaParams aiParams{}; + Arena* aiArena = ArenaAllocate(aiParams); Assert(aiArena != nullptr); size_t fileIndex = 0; @@ -927,7 +927,7 @@ namespace Romeo for (FileEntry& entry : db.Entries) { fileIndex++; - const Juliet::String& primaryPath = (entry.HeaderPath.Size > 0) ? entry.HeaderPath : entry.CppPath; + const String& primaryPath = (entry.HeaderPath.Size > 0) ? entry.HeaderPath : entry.CppPath; if (primaryPath.Size == 0) { continue; @@ -941,11 +941,11 @@ namespace Romeo continue; } - Juliet::String relStr = GetRelativeString(primaryPath, workspaceRoot); + String relStr = GetRelativeString(primaryPath, workspaceRoot); char baseName[512]; size_t copyLen = relStr.Size < 511 ? relStr.Size : 511; - memcpy(baseName, relStr.Data, copyLen); + memcpy(baseName, relStr.Str, copyLen); baseName[copyLen] = '\0'; size_t baseLen = strlen(baseName); @@ -960,7 +960,7 @@ namespace Romeo baseLen -= 2; } - Juliet::String mdFileName = BuildMarkdownFileName(db.DbArena, baseName, baseLen); + String mdFileName = BuildMarkdownFileName(db.DbArena, baseName, baseLen); fprintf(overviewFile, "- [%s](%s)\n", baseName, CStr(mdFileName)); @@ -996,11 +996,11 @@ namespace Romeo printf("Romeo: [%zu/%zu] Generating AI description for '%s'...\n", fileIndex, totalFiles, baseName); - Juliet::ArenaClear(aiArena); + ArenaClear(aiArena); if (AI_GenerateDescription(aiArena, entry)) { // Copy the description to the persistent db arena so it survives aiArena clear - entry.Description = Juliet::StringCopy(db.DbArena, entry.Description); + entry.Description = StringCopy(db.DbArena, entry.Description); entry.LastAIGeneratedTime = currentTime; printf("Romeo: [%zu/%zu] Done.\n", fileIndex, totalFiles); } @@ -1011,7 +1011,7 @@ namespace Romeo } } - Juliet::ArenaClear(tempArena); + ArenaClear(tempArena); char mdFilePath[512]; snprintf(mdFilePath, sizeof(mdFilePath), "%s\\%s", CStr(docsDir), CStr(mdFileName)); @@ -1022,20 +1022,20 @@ namespace Romeo sb.Append("## Source Files\n"); if (entry.HeaderPath.Size > 0) { - Juliet::String hRel = GetRelativeString(entry.HeaderPath, workspaceRoot); - sb.Append("- Header: `%.*s`\n", static_cast(hRel.Size), hRel.Data); + String hRel = GetRelativeString(entry.HeaderPath, workspaceRoot); + sb.Append("- Header: `%.*s`\n", static_cast(hRel.Size), hRel.Str); } if (entry.CppPath.Size > 0) { - Juliet::String cRel = GetRelativeString(entry.CppPath, workspaceRoot); - sb.Append("- Source: `%.*s`\n", static_cast(cRel.Size), cRel.Data); + String cRel = GetRelativeString(entry.CppPath, workspaceRoot); + sb.Append("- Source: `%.*s`\n", static_cast(cRel.Size), cRel.Str); } sb.Append("\n"); sb.Append("## AI Description\n"); if (entry.Description.Size > 0) { - sb.Append("%.*s\n", static_cast(entry.Description.Size), entry.Description.Data); + sb.Append("%.*s\n", static_cast(entry.Description.Size), entry.Description.Str); } else { @@ -1056,9 +1056,9 @@ namespace Romeo printf("Romeo: [%zu/%zu] Symbols done.\n", fileIndex, totalFiles); // Compare with existing file to decide if we write to disk - Juliet::String existing = ReadFileContent(tempArena, mdFilePath); - Juliet::String newContent = { sb.Buffer, sb.Size }; - if (existing.Size == 0 || Juliet::StringCompare(existing, newContent) != 0) + String existing = ReadFileContent(tempArena, mdFilePath); + String newContent = { sb.Buffer, sb.Size }; + if (existing.Size == 0 || StringCompare(existing, newContent) != 0) { FILE* mdFile = nullptr; if (fopen_s(&mdFile, mdFilePath, "wb") == 0 && mdFile) @@ -1078,8 +1078,8 @@ namespace Romeo printf("Rome: Done processing batch\n"); - Juliet::ArenaRelease(aiArena); - Juliet::ArenaRelease(tempArena); + ArenaRelease(aiArena); + ArenaRelease(tempArena); fclose(overviewFile); } } diff --git a/Romeo/src/MarkdownGenerator.h b/Romeo/src/MarkdownGenerator.h index a023149..aa49d37 100644 --- a/Romeo/src/MarkdownGenerator.h +++ b/Romeo/src/MarkdownGenerator.h @@ -1,7 +1,7 @@ -#pragma once +#pragma once #include "Database.h" namespace Romeo { - void MD_GenerateDocumentation(Database& db, const Juliet::String& workspaceRoot, const Juliet::String& docsDir); + void MD_GenerateDocumentation(Database& db, const String& workspaceRoot, const String& docsDir); } diff --git a/Romeo/src/main.cpp b/Romeo/src/main.cpp index 4b727fa..2312ce6 100644 --- a/Romeo/src/main.cpp +++ b/Romeo/src/main.cpp @@ -22,19 +22,19 @@ #define ROMEO_WM_TRAYICON (WM_USER + 1) static Romeo::Database G_Db; -static Juliet::Arena* G_ScratchArena = nullptr; -static Juliet::String G_WorkspaceRoot; -static Juliet::String G_DocsDir; -static Juliet::String G_DbFilePath; +static Arena* G_ScratchArena = nullptr; +static String G_WorkspaceRoot; +static String G_DocsDir; +static String G_DbFilePath; -static Juliet::String GetWorkspaceRoot(Juliet::Arena* arena) +static String GetWorkspaceRoot(Arena* arena) { Assert(arena != nullptr); - Juliet::String base = Juliet::GetBasePath(); + String base = GetBasePath(); // Copy to arena so we can safely modify it - char* buf = Juliet::ArenaPushArray(arena, base.Size + 1 JULIET_DEBUG_PARAM("WorkspaceRootPath")); - memcpy(buf, base.Data, base.Size); + char* buf = ArenaPushArray(arena, base.Size + 1 JULIET_DEBUG_PARAM("WorkspaceRootPath")); + memcpy(buf, base.Str, base.Size); buf[base.Size] = '\0'; // Normalize slashes @@ -205,8 +205,8 @@ static void MonitorThreadProc() OutputDebugStringA("Romeo Monitor: Change detected, updating...\n"); { - Juliet::LockGuard lock(G_Db.Mutex); - Juliet::ArenaClear(G_ScratchArena); + LockGuard lock(G_Db.Mutex); + ArenaClear(G_ScratchArena); Romeo::DB_ScanWorkspace(G_Db, G_ScratchArena, G_WorkspaceRoot); @@ -413,11 +413,11 @@ int JulietMain(int argc, wchar_t** argv) } } - Juliet::ArenaParams params{}; - Juliet::Arena* mainArena = Juliet::ArenaAllocate(params JULIET_DEBUG_PARAM("RomeoMainArena")); + ArenaParams params{}; + Arena* mainArena = ArenaAllocate(params); Assert(mainArena != nullptr); - G_ScratchArena = Juliet::ArenaAllocate(params JULIET_DEBUG_PARAM("RomeoScratchArena")); + G_ScratchArena = ArenaAllocate(params); Assert(G_ScratchArena != nullptr); printf("Arena Allocated! Pointer: %p\n", static_cast(mainArena)); @@ -426,11 +426,11 @@ int JulietMain(int argc, wchar_t** argv) char docsDirBuf[512]; snprintf(docsDirBuf, sizeof(docsDirBuf), "%s\\Romeo\\docs", CStr(G_WorkspaceRoot)); - G_DocsDir = Juliet::StringCopy(mainArena, Juliet::WrapString(docsDirBuf)); + G_DocsDir = StringCopy(mainArena, WrapString(docsDirBuf)); char dbFilePathBuf[512]; snprintf(dbFilePathBuf, sizeof(dbFilePathBuf), "%s\\Romeo\\docs\\romeo.db", CStr(G_WorkspaceRoot)); - G_DbFilePath = Juliet::StringCopy(mainArena, Juliet::WrapString(dbFilePathBuf)); + G_DbFilePath = StringCopy(mainArena, WrapString(dbFilePathBuf)); Romeo::DB_Init(G_Db, mainArena); @@ -443,7 +443,7 @@ int JulietMain(int argc, wchar_t** argv) } { - Juliet::LockGuard lock(G_Db.Mutex); + LockGuard lock(G_Db.Mutex); if (!forceRegenerate) { Romeo::DB_Load(G_Db, G_DbFilePath); @@ -559,8 +559,8 @@ int JulietMain(int argc, wchar_t** argv) G_OllamaJobHandle = nullptr; } - Juliet::ArenaRelease(mainArena); - Juliet::ArenaRelease(G_ScratchArena); + ArenaRelease(mainArena); + ArenaRelease(G_ScratchArena); CloseHandle(hMutex);