Added first pass on swap chain. Still needs Render Target View and various stuff.

+ Reformat all files
This commit is contained in:
2025-02-09 22:19:17 -05:00
parent d5e09e28bf
commit d90a0bdf83
37 changed files with 944 additions and 636 deletions

View File

@@ -30,8 +30,7 @@ namespace Game
};
template <typename EntityType>
concept EntityConcept = requires(EntityType entity)
{
concept EntityConcept = requires(EntityType entity) {
requires std::same_as<decltype(entity.Kind), const Juliet::Class*>;
requires std::same_as<decltype(entity.Base), Entity*>;
};

View File

@@ -13,7 +13,7 @@ namespace Game
// May be this should contains the allocator for each entity types
};
void InitEntityManager();\
void InitEntityManager();
EntityManager& GetEntityManager();
void RegisterEntity(EntityManager& manager, Entity* entity);
}
} // namespace Game

View File

@@ -140,7 +140,6 @@
<ClInclude Include="include\pch.h"/>
<ClInclude Include="src\Core\HAL\Display\DisplayDevice.h"/>
<ClInclude Include="src\Core\HAL\Display\Display_Private.h"/>
<ClInclude Include="src\Core\HAL\Display\Win32\Win32DisplayDevice.h" />
<ClInclude Include="src\Core\HAL\Display\Win32\Win32DisplayEvent.h"/>
<ClInclude Include="src\Core\HAL\Display\Win32\Win32Window.h"/>
<ClInclude Include="src\Core\HAL\Display\Window.h"/>
@@ -154,6 +153,7 @@
<ClInclude Include="src\Graphics\D3D12\DX12CommandList.h"/>
<ClInclude Include="src\Graphics\D3D12\DX12GraphicsDevice.h"/>
<ClInclude Include="src\Graphics\D3D12\DX12Includes.h"/>
<ClInclude Include="src\Graphics\D3D12\DX12SwapChain.h"/>
<ClInclude Include="src\Graphics\D3D12\DX12Utils.h"/>
<ClInclude Include="src\Graphics\GraphicsDevice.h"/>
</ItemGroup>
@@ -234,6 +234,8 @@
<ClCompile Include="src\Engine\Engine.cpp"/>
<ClCompile Include="src\Graphics\D3D12\DX12CommandList.cpp"/>
<ClCompile Include="src\Graphics\D3D12\DX12GraphicsDevice.cpp"/>
<ClCompile Include="src\Graphics\D3D12\DX12SwapChain.cpp"/>
<ClCompile Include="src\Graphics\D3D12\DX12Utils.cpp" />
<ClCompile Include="src\Graphics\Graphics.cpp">
<RuntimeLibrary>MultiThreadedDebugDll</RuntimeLibrary>
<Optimization>Disabled</Optimization>

View File

@@ -1,7 +1,7 @@
#pragma once
#include <Juliet.h>
#include <Core/Common/CoreTypes.h>
#include <Juliet.h>
namespace Juliet
{

View File

@@ -5,7 +5,8 @@
namespace Juliet
{
// TODO : Create my own Vector class based on https://github.com/niklas-ourmachinery/bitsquid-foundation/blob/master/collection_types.h
template <typename T> class Vector : public std::vector<T>
template <typename T>
class Vector : public std::vector<T>
{
};
} // namespace Juliet

View File

@@ -1,8 +1,8 @@
#pragma once
#include <Juliet.h>
#include <Core/Common/CoreTypes.h>
#include <core/Common/NonNullPtr.h>
#include <Juliet.h>
namespace Juliet
{

View File

@@ -7,6 +7,7 @@
// Graphics Interface
namespace Juliet
{
struct Window;
struct GraphicsDevice;
// Parameters of an indirect draw command
@@ -45,11 +46,16 @@ namespace Juliet
};
// Opaque types
struct CommandList {};
struct CommandList;
extern JULIET_API GraphicsDevice* CreateGraphicsDevice(GraphicsConfig config);
extern JULIET_API void DestroyGraphicsDevice(NonNullPtr<GraphicsDevice> device);
// Attach To Window
extern JULIET_API bool AttachToWindow(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window);
extern JULIET_API void DetachFromWindow(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window);
// Command List
extern JULIET_API CommandList* AcquireCommandList(NonNullPtr<GraphicsDevice> device, QueueType queueType = QueueType::Graphics);
extern JULIET_API void SubmitCommandLists(NonNullPtr<GraphicsDevice> device);
} // namespace Juliet

View File

@@ -7,10 +7,10 @@
#ifndef PCH_H
#define PCH_H
#include <Juliet.h>
#include <Core/Common/CoreTypes.h>
#include <Core/Common/CoreUtils.h>
#include <Core/Logging/LogManager.h>
#include <Core/Logging/LogTypes.h>
#include <Juliet.h>
#endif // PCH_H

View File

@@ -7,4 +7,4 @@ namespace Juliet
Juliet::Log(Juliet::LogLevel::Error, Juliet::LogCategory::Core, expression);
__debugbreak();
}
}
} // namespace Juliet

View File

@@ -21,8 +21,7 @@ namespace Juliet
Assert(!CurrentDisplayDevice);
DisplayDevice* candidateDevice = nullptr;
DisplayDeviceFactory*
candidateFactory = nullptr;
DisplayDeviceFactory* candidateFactory = nullptr;
for (DisplayDeviceFactory* factory : Factories)
{
if (factory)

View File

@@ -1,7 +1,6 @@
#include <pch.h>
#include <Core/HAL/Display/DisplayDevice.h>
#include <Core/HAL/Display/Win32/Win32DisplayDevice.h>
#include <Core/HAL/Display/Win32/Win32DisplayEvent.h>
#include <Core/HAL/Display/Win32/Win32Window.h>
#include <Core/Memory/Allocator.h>

View File

@@ -1,6 +0,0 @@
#pragma once
namespace Juliet::Win32
{
}

View File

@@ -3,7 +3,6 @@
#include <Core/HAL/Display/Win32/Win32DisplayEvent.h>
#include <Core/HAL/Display/Win32/Win32Window.h>
#include <Core/HAL/Display/Window.h>
#include <Core/HAL/Win32.h>
#include <Core/Memory/Allocator.h>
namespace Juliet::Win32

View File

@@ -2,6 +2,7 @@
#include <Core/Common/NonNullPtr.h>
#include <Core/HAL/Display/Window.h>
#include <Core/HAL/Win32.h>
namespace Juliet
{

View File

@@ -7,7 +7,11 @@
namespace Juliet
{
Socket::Socket(Protocol protocol) : Handle(SocketImpl::GetInvalidSocketHandle()), ProtocolType(protocol) {}
Socket::Socket(Protocol protocol)
: Handle(SocketImpl::GetInvalidSocketHandle())
, ProtocolType(protocol)
{
}
Socket::~Socket()
{

View File

@@ -7,7 +7,10 @@
namespace Juliet
{
TcpListener::TcpListener() : Socket(Protocol::TCP) {}
TcpListener::TcpListener()
: Socket(Protocol::TCP)
{
}
Socket::Status TcpListener::Listen(uint16 port, uint32 address)
{

View File

@@ -8,7 +8,10 @@
namespace Juliet
{
TcpSocket::TcpSocket() : Socket(Protocol::TCP) {}
TcpSocket::TcpSocket()
: Socket(Protocol::TCP)
{
}
Socket::RequestStatus TcpSocket::Send(NetworkPacket& packet)
{

View File

@@ -54,8 +54,7 @@ Socket::Status GetErrorStatus()
case WSAETIMEDOUT: return Socket::Status::Disconnected;
case WSAENETRESET: return Socket::Status::Disconnected;
case WSAENOTCONN: return Socket::Status::Disconnected;
case WSAEISCONN:
return Socket::Status::Done; // when connecting a non-blocking socket
case WSAEISCONN: return Socket::Status::Done; // when connecting a non-blocking socket
default: return Socket::Status::Error;
}
}

View File

@@ -120,10 +120,21 @@ namespace Juliet::D3D12
return reinterpret_cast<CommandList*>(commandList);
}
void SubmitCommandLists(NonNullPtr<GPUDriver> driver)
bool SubmitCommandLists(NonNullPtr<GPUDriver> driver)
{
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
bool success = true;
uint8 commandLastIndex = d3d12Driver->CommandListCount;
// TODO : Get window data from the command list: We associate the swapchain texture to a window with a missing function
HRESULT result = IDXGISwapChain_Present(d3d12Driver->WindowData->SwapChain, 0, 1);
if (FAILED(result))
{
success = false;
}
return success;
}
} // namespace Juliet::D3D12

View File

@@ -21,5 +21,5 @@ namespace Juliet::D3D12
};
extern CommandList* AcquireCommandList(NonNullPtr<GPUDriver> driver, QueueType queueType);
extern void SubmitCommandLists(NonNullPtr<GPUDriver> driver);
extern bool SubmitCommandLists(NonNullPtr<GPUDriver> driver);
} // namespace Juliet::D3D12

View File

@@ -6,6 +6,7 @@
#include <Graphics/D3D12/DX12CommandList.h>
#include <Graphics/D3D12/DX12GraphicsDevice.h>
#include <Graphics/D3D12/DX12Includes.h>
#include <Graphics/D3D12/DX12SwapChain.h>
#include <Graphics/Graphics.h>
#include <Graphics/GraphicsDevice.h>
@@ -219,6 +220,53 @@ namespace Juliet::D3D12
Free(driver.Get());
}
bool AttachToWindow(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window)
{
auto* d3d12Driver = static_cast<D3D12Driver*>(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<D3D12WindowData*>(Calloc(1, sizeof(D3D12WindowData)));
if (!windowData)
{
Log(LogLevel::Error, LogCategory::Graphics, "OOM: D3D12WindowData");
return false;
}
windowData->Window = window;
if (!CreateSwapChain(d3d12Driver, windowData))
{
Log(LogLevel::Error, LogCategory::Graphics, "AttachToWindow failure: Cannot create Swap Chain.");
Free(windowData);
return false;
}
d3d12Driver->WindowData = windowData;
// TODO : React to resize. Need event system.
return true;
}
void DetachFromWindow(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window)
{
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
Assert(d3d12Driver->WindowData && "Trying to destroy a swapchain but no Window Data exists");
// TODO : Wait for any remaining work and release the fences.
DestroySwapChain(d3d12Driver, d3d12Driver->WindowData);
Free(d3d12Driver->WindowData);
d3d12Driver->WindowData = nullptr;
}
void DestroyGraphicsDevice(NonNullPtr<GraphicsDevice> device)
{
// Note: Its a down cast so clang suggest not to do it but we are totally sure about it.
@@ -469,12 +517,18 @@ namespace Juliet::D3D12
// Assign Functions to the device
device->DestroyDevice = DestroyGraphicsDevice;
device->AttachToWindow = AttachToWindow;
device->DetachFromWindow = DetachFromWindow;
device->AcquireCommandList = AcquireCommandList;
device->SubmitCommandLists = SubmitCommandLists;
device->Driver = driver;
driver->GraphicsDevice = device;
driver->FramesInFlight = 2;
return device;
}
} // namespace

View File

@@ -1,6 +1,7 @@
#pragma once
#include <DX12Utils.h>
#include <Core/Common/EnumUtils.h>
#include <Graphics/D3D12/DX12Utils.h>
#include <Graphics/GraphicsDevice.h>
namespace Juliet
@@ -10,6 +11,18 @@ namespace Juliet
namespace Juliet::D3D12
{
struct D3D12CommandList;
struct D3D12WindowData
{
Window* Window;
IDXGISwapChain3* SwapChain;
uint8 SwapChainTextureCount;
uint32 FrameCounter;
};
struct D3D12Driver : GPUDriver
{
GraphicsDevice* GraphicsDevice;
@@ -35,16 +48,19 @@ namespace Juliet::D3D12
IDXGIInfoQueue* DXGIInfoQueue;
#endif
// Windows
// TODO: Support more than one window
D3D12WindowData* WindowData;
// Resources
D3D12CommandList** AvailableCommandLists;
uint8 AvailableCommandListCapacity;
bool IsTearingSupported : 1;
uint8 FramesInFlight;
// UMA
bool IsTearingSupported : 1;
bool IsUMAAvailable : 1;
bool IsUMACacheCoherent : 1;
bool GPUUploadHeapSupported : 1;
};
} // namespace Juliet::D3D12

View File

@@ -12,10 +12,10 @@
#define CINTERFACE ;
#include <d3dcompiler.h>
#include "d3d12.h"
#include <DirectXMath.h>
#include <dxgi1_5.h>
#include <dxgi1_6.h>
#include "d3d12.h"
#ifdef _DEBUG
#include <dxgidebug.h>

View File

@@ -0,0 +1,104 @@
#include <pch.h>
#include <Core/HAL/Display/Win32/Win32Window.h>
#include <Graphics/D3D12/DX12GraphicsDevice.h>
#include <Graphics/D3D12/DX12SwapChain.h>
#include <algorithm>
namespace Juliet::D3D12
{
bool CreateSwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData)
{
auto windowWin32State = static_cast<Win32::Window32State*>(windowData->Window->State);
HWND windowHandle = windowWin32State->Handle;
if (!IsWindow(windowHandle))
{
Assert(false && "windowWin32State->Handle is not a window handle ???");
return false;
}
// SDR.
// TODO: Not enough for HDR. but i have no way to test HDR easily except the steamdeck
DXGI_FORMAT swapChainFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
windowData->SwapChainTextureCount = std::clamp<uint8>(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 =
IDXGIFactory4_CreateSwapChainForHwnd(driver->DXGIFactory, reinterpret_cast<IUnknown*>(driver->GraphicsQueue),
windowHandle, &swapChainDesc, &swapChainFullscreenDesc, nullptr, &swapChain);
if (FAILED(result))
{
LogError(driver, "Failed to create SwapChain", result);
return false;
}
IDXGISwapChain3* swapChain3 = nullptr;
result = IDXGISwapChain1_QueryInterface(swapChain, IID_IDXGISwapChain3, reinterpret_cast<void**>(&swapChain3));
IDXGISwapChain1_Release(swapChain);
if (FAILED(result))
{
LogError(driver, "Could not query IDXGISwapChain3 interface", result);
return false;
}
IDXGIFactory1* parentFactory = nullptr;
result = IDXGISwapChain3_GetParent(swapChain3, IID_IDXGIFactory1, reinterpret_cast<void**>(&parentFactory));
if (FAILED(result))
{
Log(LogLevel::Warning, LogCategory::Graphics, "Cannot get SwapChain Parent! Error Code: " HRESULT_FMT, result);
}
else
{
// Disable DXGI window crap
result = IDXGIFactory1_MakeWindowAssociation(parentFactory, windowHandle, DXGI_MWA_NO_WINDOW_CHANGES);
if (FAILED(result))
{
Log(LogLevel::Warning, LogCategory::Graphics, "MakeWindowAssociation failed! Error Code: " HRESULT_FMT, result);
}
IDXGIFactory1_Release(parentFactory);
}
IDXGISwapChain3_GetDesc1(swapChain3, &swapChainDesc);
if (FAILED(result))
{
LogError(driver, "Failed to retrieve SwapChain descriptor", result);
return false;
}
windowData->SwapChain = swapChain3;
windowData->FrameCounter = 0;
return true;
}
void DestroySwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData) {}
} // namespace Juliet::D3D12

View File

@@ -0,0 +1,11 @@
#pragma once
#include <Core/Common/NonNullPtr.h>
namespace Juliet::D3D12
{
struct D3D12Driver;
struct D3D12WindowData;
extern bool CreateSwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData);
extern void DestroySwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData);
}

View File

@@ -0,0 +1,61 @@
#include <pch.h>
#include <Core/Common/NonNullPtr.h>
#include <DX12GraphicsDevice.h>
#include <Graphics/D3D12/DX12Utils.h>
#include <algorithm>
namespace Juliet::D3D12
{
// From SDLGPU
// TODO Do my own version.
extern void LogError(NonNullPtr<D3D12Driver> driver, 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];
DWORD dwChars; // Number of chars returned.
if (result == DXGI_ERROR_DEVICE_REMOVED)
{
if (driver->D3D12Device)
{
result = ID3D12Device_GetDeviceRemovedReason(driver->D3D12Device);
}
}
// Try to get the message from the system errors.
dwChars = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, result, 0,
wszMsgBuff, MAX_ERROR_LEN, NULL);
// 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 = std::min<DWORD>(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);
}
} // namespace Juliet::D3D12

View File

@@ -2,8 +2,16 @@
#include <Graphics/D3D12/DX12Includes.h>
namespace Juliet
#ifdef _WIN32
#define HRESULT_FMT "(0x%08lX)"
#else
#define HRESULT_FMT "(0x%08X)"
#endif
namespace Juliet::D3D12
{
struct D3D12Driver;
inline void AssertOnFailure(HRESULT hr)
{
Assert(!!FAILED(hr));
@@ -16,4 +24,6 @@ namespace Juliet
case E_POINTER: Assert(false && "Invalid Pointer");
}
}
} // namespace Juliet::RHI::DX12
extern void LogError(NonNullPtr<D3D12Driver> driver, const char* errorMessage, HRESULT result);
} // namespace Juliet::D3D12

View File

@@ -63,6 +63,20 @@ namespace Juliet
device->DestroyDevice(device);
}
bool AttachToWindow(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window)
{
GPUDriver* driver = device->Driver;
bool result = device->AttachToWindow(driver, window);
return result;
}
void DetachFromWindow(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window)
{
GPUDriver* driver = device->Driver;
device->DetachFromWindow(driver, window);
}
CommandList* AcquireCommandList(NonNullPtr<GraphicsDevice> device, QueueType queueType /* = QueueType::Graphics */)
{
GPUDriver* driver = device->Driver;

View File

@@ -6,6 +6,8 @@
namespace Juliet
{
struct Window;
struct GPUDriver
{
uint8 CommandListCount;
@@ -16,8 +18,14 @@ namespace Juliet
struct GraphicsDevice
{
void (*DestroyDevice)(NonNullPtr<GraphicsDevice> self);
// Attach to window
bool (*AttachToWindow)(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window);
void (*DetachFromWindow)(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window);
// CommandLists
CommandList* (*AcquireCommandList)(NonNullPtr<GPUDriver> driver, QueueType queueType);
void (*SubmitCommandLists)(NonNullPtr<GPUDriver> driver);
bool (*SubmitCommandLists)(NonNullPtr<GPUDriver> driver);
const char* Name = "Unknown";
GPUDriver* Driver = nullptr;

View File

@@ -31,18 +31,28 @@ void Win32EditorApplication::Init()
MainWindow = CreatePlatformWindow("Juliet Editor", 1280, 720);
// TODO : Assign the graphics device to the main window (and detach)
Running = MainWindow != nullptr && GraphicsDevice != nullptr;
DynamicLibrary = LoadDynamicLibrary("Game.dll");
if (Running)
{
AttachToWindow(GraphicsDevice, MainWindow);
Game = LoadDynamicLibrary("Game.dll");
}
}
void Win32EditorApplication::Shutdown()
{
Log(LogLevel::Message, LogCategory::Editor, "Shutdown Editor Application...");
UnloadDynamicLibrary(DynamicLibrary);
if (Game)
{
UnloadDynamicLibrary(Game);
}
if (MainWindow && GraphicsDevice)
{
DetachFromWindow(GraphicsDevice, MainWindow);
}
if (MainWindow)
{

View File

@@ -8,7 +8,7 @@ namespace Juliet
{
struct GraphicsDevice;
struct Window;
}
} // namespace Juliet
class Win32EditorApplication : public Juliet::IApplication
{
@@ -21,7 +21,7 @@ class Win32EditorApplication : public Juliet::IApplication
private:
Juliet::Window* MainWindow = {};
Juliet::GraphicsDevice* GraphicsDevice = {};
Juliet::DynamicLibrary* DynamicLibrary = {};
Juliet::DynamicLibrary* Game = {};
bool Running = false;
};