diff --git a/Juliet/Juliet.vcxproj b/Juliet/Juliet.vcxproj
index 7a94569..6e4dc40 100644
--- a/Juliet/Juliet.vcxproj
+++ b/Juliet/Juliet.vcxproj
@@ -134,9 +134,11 @@
+
-
+
+
@@ -151,8 +153,10 @@
-
-
+
+
+
+
@@ -235,12 +239,14 @@
-
-
+
+
+
+
-
+
MultiThreadedDebugDll
Disabled
@@ -302,7 +308,7 @@
-
+
diff --git a/Juliet/include/Core/Common/CoreTypes.h b/Juliet/include/Core/Common/CoreTypes.h
index e4a9e59..85d34de 100644
--- a/Juliet/include/Core/Common/CoreTypes.h
+++ b/Juliet/include/Core/Common/CoreTypes.h
@@ -2,6 +2,7 @@
#include
#include
+#include
using uint8 = uint8_t;
using uint16 = uint16_t;
@@ -24,3 +25,14 @@ struct ByteBuffer
};
using FunctionPtr = auto (*)(void) -> void;
+
+// Limits
+template
+consteval Type MaxValueOf()
+{
+ return std::numeric_limits::max();
+}
+constexpr uint32 uint8Max = MaxValueOf();
+constexpr uint32 uint16Max = MaxValueOf();
+constexpr uint32 uint32Max = MaxValueOf();
+constexpr uint32 uint64Max = MaxValueOf();
diff --git a/Juliet/include/Core/Common/CoreUtils.h b/Juliet/include/Core/Common/CoreUtils.h
index 8d24753..14f0de0 100644
--- a/Juliet/include/Core/Common/CoreUtils.h
+++ b/Juliet/include/Core/Common/CoreUtils.h
@@ -1,5 +1,6 @@
#pragma once
+#include
#include
#include
@@ -35,4 +36,30 @@ namespace Juliet
}
#define MemCopy memcpy
+
+ 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 Clamp(Type val, Type min, Type max)
+ {
+ if (val < min)
+ {
+ return min;
+ }
+ if (val > max)
+ {
+ return max;
+ }
+ return val;
+ }
} // namespace Juliet
diff --git a/Juliet/include/Graphics/Colors.h b/Juliet/include/Graphics/Colors.h
new file mode 100644
index 0000000..eae255b
--- /dev/null
+++ b/Juliet/include/Graphics/Colors.h
@@ -0,0 +1,16 @@
+#pragma once
+
+namespace Juliet
+{
+ template
+ struct ColorType
+ {
+ Type R;
+ Type G;
+ Type B;
+ Type A;
+ };
+
+ using FColor = ColorType;
+ using Color = ColorType;
+} // namespace Juliet
diff --git a/Juliet/include/Graphics/Graphics.h b/Juliet/include/Graphics/Graphics.h
index e13bc56..7333222 100644
--- a/Juliet/include/Graphics/Graphics.h
+++ b/Juliet/include/Graphics/Graphics.h
@@ -1,14 +1,16 @@
#pragma once
#include
+#include
#include
-#include
+#include
#include
// Graphics Interface
namespace Juliet
{
- struct Window;
+ // Opaque types
+ struct CommandList;
struct GraphicsDevice;
// Parameters of an indirect draw command
@@ -65,9 +67,6 @@ namespace Juliet
Immediate
};
- // Opaque types
- struct CommandList;
-
extern JULIET_API GraphicsDevice* CreateGraphicsDevice(GraphicsConfig config);
extern JULIET_API void DestroyGraphicsDevice(NonNullPtr device);
@@ -82,4 +81,9 @@ namespace Juliet
// Command List
extern JULIET_API CommandList* AcquireCommandList(NonNullPtr device, QueueType queueType = QueueType::Graphics);
extern JULIET_API void SubmitCommandLists(NonNullPtr device);
+
+ // RenderPass
+ extern JULIET_API RenderPass* BeginRenderPass(NonNullPtr commandList, ColorTargetInfo& colorTargetInfo);
+ extern JULIET_API RenderPass* BeginRenderPass(NonNullPtr commandList,
+ NonNullPtr colorTargetInfos, uint32 colorTargetInfoCount);
} // namespace Juliet
diff --git a/Juliet/include/Graphics/RenderPass.h b/Juliet/include/Graphics/RenderPass.h
new file mode 100644
index 0000000..fd433bb
--- /dev/null
+++ b/Juliet/include/Graphics/RenderPass.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include
+#include
+
+namespace Juliet
+{
+ 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* Texture;
+ uint32 MipLevel;
+ union
+ {
+ uint32 DepthPlane;
+ uint32 LayerCount;
+ };
+ FColor ClearColor;
+ LoadOperation LoadOperation;
+ StoreOperation StoreOperation;
+ bool Cycle; // Whether the texture should be cycled if already bound (and load operation != LOAD)
+ };
+
+ // Opaque Type
+ struct RenderPass;
+} // namespace Juliet
diff --git a/Juliet/include/Graphics/Texture.h b/Juliet/include/Graphics/Texture.h
index 628e8ae..0eb333e 100644
--- a/Juliet/include/Graphics/Texture.h
+++ b/Juliet/include/Graphics/Texture.h
@@ -161,9 +161,9 @@ namespace Juliet
// Create Information structs
struct TextureCreateInfo
{
- TextureType Type;
- TextureFormat Format;
- TextureUsageFlag Flags;
+ TextureType Type;
+ TextureFormat Format;
+ TextureUsageFlag Flags;
TextureSampleCount SampleCount;
uint32 Width;
@@ -171,10 +171,11 @@ namespace Juliet
union
{
uint32 LayerCount;
- uint32 Depth;
+ uint32 DepthPlane;
}; // LayerCount is used in 2d array textures and Depth for 3d textures
uint32 MipLevelCount;
};
+ // Opaque Type
struct Texture;
} // namespace Juliet
diff --git a/Juliet/src/Core/HAL/Win32.h b/Juliet/src/Core/HAL/Win32.h
index 28b3cc4..509429a 100644
--- a/Juliet/src/Core/HAL/Win32.h
+++ b/Juliet/src/Core/HAL/Win32.h
@@ -58,3 +58,6 @@
#define ANSI_ONLY
#include
+
+#undef min
+#undef max
diff --git a/Juliet/src/Graphics/D3D12/D3D12Common.h b/Juliet/src/Graphics/D3D12/D3D12Common.h
index 7afddca..c04feff 100644
--- a/Juliet/src/Graphics/D3D12/D3D12Common.h
+++ b/Juliet/src/Graphics/D3D12/D3D12Common.h
@@ -14,8 +14,8 @@
// Inspired (copy pasted a lot) by SDL GPU
namespace Juliet::D3D12
{
- struct D3D12Driver;
// Forward declare
+ struct D3D12Driver;
struct D3D12StagingDescriptor;
// https://learn.microsoft.com/en-us/windows/win32/direct3d12/descriptor-heaps
diff --git a/Juliet/src/Graphics/D3D12/D3D12RenderPass.cpp b/Juliet/src/Graphics/D3D12/D3D12RenderPass.cpp
new file mode 100644
index 0000000..a091dc9
--- /dev/null
+++ b/Juliet/src/Graphics/D3D12/D3D12RenderPass.cpp
@@ -0,0 +1,57 @@
+#include
+
+#include
+#include
+
+#include
+
+namespace Juliet::D3D12
+{
+ void BeginRenderPass(NonNullPtr commandList, NonNullPtr colorTargetInfos, uint32 colorTargetInfoCount)
+ {
+ 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].Texture);
+ 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);
+ }
+
+ // TODO : Depth Stencil and DSV
+
+ D3D12_CPU_DESCRIPTOR_HANDLE RTVs[GPUDriver::kMaxColorTargetInfo];
+ for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx)
+ {
+ auto* container = reinterpret_cast(colorTargetInfos[idx].Texture);
+ D3D12TextureSubresource* subresource = PrepareTextureSubresourceForWrite(
+ d3d12CommandList, container,
+ container->Header.CreateInfo.Type == TextureType::Texture_3D ? 0 : colorTargetInfos[idx].LayerCount,
+ colorTargetInfos[idx].MipLevel, colorTargetInfos[idx].Cycle, 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;
+
+ ID3D12GraphicsCommandList6_ClearRenderTargetView(d3d12CommandList->GraphicsCommandList.CommandList, rtv, clearColor, 0, nullptr);
+ }
+
+ RTVs[idx] = rtv;
+ // d3d12CommandList->ColorTargetSubresources[idx] = subresource;
+ }
+ }
+} // namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/D3D12/D3D12RenderPass.h b/Juliet/src/Graphics/D3D12/D3D12RenderPass.h
new file mode 100644
index 0000000..97784db
--- /dev/null
+++ b/Juliet/src/Graphics/D3D12/D3D12RenderPass.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include
+#include
+#include
+
+namespace Juliet::D3D12
+{
+ extern void BeginRenderPass(NonNullPtr commandList, NonNullPtr colorTargetInfos,
+ uint32 colorTargetInfoCount);
+}
diff --git a/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp b/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp
new file mode 100644
index 0000000..b8778a5
--- /dev/null
+++ b/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp
@@ -0,0 +1,41 @@
+#include
+
+#include
+#include
+
+namespace Juliet::D3D12
+{
+ 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)
+ {
+ ID3D12GraphicsCommandList_ResourceBarrier(commandList->GraphicsCommandList.CommandList, numBarriers, barrierDesc);
+ }
+ }
+} // namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/D3D12/D3D12Synchronization.h b/Juliet/src/Graphics/D3D12/D3D12Synchronization.h
new file mode 100644
index 0000000..c10b56d
--- /dev/null
+++ b/Juliet/src/Graphics/D3D12/D3D12Synchronization.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include
+#include
+
+namespace Juliet::D3D12
+{
+ // Forward Declare
+ struct D3D12CommandList;
+
+ extern void ResourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState, D3D12_RESOURCE_STATES destinationState,
+ ID3D12Resource* resource, uint32 subresourceIndex, bool needsUavBarrier);
+}
+
diff --git a/Juliet/src/Graphics/D3D12/D3D12Texture.cpp b/Juliet/src/Graphics/D3D12/D3D12Texture.cpp
index 7400dfc..c3ef383 100644
--- a/Juliet/src/Graphics/D3D12/D3D12Texture.cpp
+++ b/Juliet/src/Graphics/D3D12/D3D12Texture.cpp
@@ -1,8 +1,102 @@
#include
+#include
#include
+#include
namespace Juliet::D3D12
{
+ namespace
+ {
+ uint32 ComputeSubresourceIndex(uint32 mipLevel, uint32 layer, uint32 numLevels)
+ {
+ return mipLevel + (layer * numLevels);
+ }
-}
\ No newline at end of file
+ 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;
+ }
+
+ void SetTextureSubresourceTransitionFromDefault(NonNullPtr commandList,
+ NonNullPtr subresource,
+ D3D12_RESOURCE_STATES newTextureUsage)
+ {
+ D3D12_RESOURCE_STATES defaultUsage =
+ GetDefaultTextureResourceState(subresource->Parent->Container->Header.CreateInfo.Flags);
+ TextureSubresourceBarrier(commandList, defaultUsage, newTextureUsage, subresource);
+ }
+
+ void SetTextureTransitionFromDefault(NonNullPtr commandList, NonNullPtr texture,
+ D3D12_RESOURCE_STATES newTextureUsage)
+ {
+ for (uint32 i = 0; i < texture->SubresourceCount; ++i)
+ {
+ SetTextureSubresourceTransitionFromDefault(commandList, &texture->Subresources[i], newTextureUsage);
+ }
+ }
+ } // namespace
+
+ 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->RefCount > 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);
+ }
+
+ SetTextureSubresourceTransitionFromDefault(commandList, subresource, newTextureUsage);
+
+ return subresource;
+ }
+
+ 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);
+ }
+} // namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/D3D12/D3D12Texture.h b/Juliet/src/Graphics/D3D12/D3D12Texture.h
index d94cf47..66435fa 100644
--- a/Juliet/src/Graphics/D3D12/D3D12Texture.h
+++ b/Juliet/src/Graphics/D3D12/D3D12Texture.h
@@ -8,9 +8,10 @@ struct ID3D12Resource;
namespace Juliet::D3D12
{
+ // Forward Declare
struct D3D12Texture;
-
struct D3D12ResourceHeap;
+ struct D3D12CommandList;
struct D3D12TextureContainer
{
@@ -30,7 +31,7 @@ namespace Juliet::D3D12
};
// D3D12 subresourcces: https://learn.microsoft.com/en-us/windows/win32/direct3d12/subresources (mipmaps, etc..)
- using D3D12TextureSubresource = struct D3D12TextureSubresource
+ struct D3D12TextureSubresource
{
D3D12Texture* Parent;
uint32 Layer;
@@ -60,4 +61,13 @@ namespace Juliet::D3D12
// TODO: Should be atomic to support multithreading
int32 RefCount;
};
+
+ extern D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr,
+ NonNullPtr container,
+ uint32 layer, uint32 level, bool shouldCycle,
+ D3D12_RESOURCE_STATES newTextureUsage);
+ extern D3D12TextureSubresource* FetchTextureSubresource(NonNullPtr container, uint32 layer, uint32 level);
+ extern void TextureSubresourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState,
+ D3D12_RESOURCE_STATES destinationState,
+ NonNullPtr textureSubresource);
} // namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/D3D12/DX12CommandList.cpp b/Juliet/src/Graphics/D3D12/DX12CommandList.cpp
index 1c725c8..2e6ab14 100644
--- a/Juliet/src/Graphics/D3D12/DX12CommandList.cpp
+++ b/Juliet/src/Graphics/D3D12/DX12CommandList.cpp
@@ -3,67 +3,105 @@
#include
#include
#include
-
+#define IID_PPV_ARGS(ppType) __uuidof(decltype(**(ppType))), reinterpret_cast(ppType)
+#define PPV_ARGS(x) IID_PPV_ARGS(&x)
namespace Juliet::D3D12
{
namespace
{
bool HasD3D12CommandList(NonNullPtr commandList, QueueType queueType)
{
- return commandList->CommandLists[ToUnderlying(queueType)] != nullptr;
+ 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;
+ }
}
- bool CreateD3D12CommandList(NonNullPtr driver, NonNullPtr commandList, QueueType queueType)
+ bool CreateAllocator(NonNullPtr driver, NonNullPtr baseData,
+ D3D12_COMMAND_QUEUE_DESC queueDesc)
{
- HRESULT res = 0;
- auto& queueDesc = driver->QueueDesc[ToUnderlying(queueType)];
- for (auto& buffer : commandList->CommandAllocator)
+ for (auto& buffer : baseData->Allocator)
{
- res = ID3D12Device5_CreateCommandAllocator(driver->D3D12Device, queueDesc.Type, IID_ID3D12CommandAllocator,
- reinterpret_cast(&buffer[ToUnderlying(queueType)]));
-
- if (FAILED(res))
+ HRESULT result = ID3D12Device5_CreateCommandAllocator(driver->D3D12Device, queueDesc.Type, IID_ID3D12CommandAllocator,
+ reinterpret_cast(&buffer));
+ if (FAILED(result))
{
Assert(false && "Error not implemented: cannot create ID3D12CommandAllocator");
return false;
}
}
+ return true;
+ }
- auto& commandListSlot = commandList->CommandLists[ToUnderlying(queueType)];
- if (queueType == QueueType::Graphics || queueType == QueueType::Compute)
- {
- ID3D12GraphicsCommandList6* d3d12GraphicsCommandList = nullptr;
- res = ID3D12Device5_CreateCommandList1(driver->D3D12Device, queueDesc.NodeMask, queueDesc.Type,
- D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList6,
- reinterpret_cast(&d3d12GraphicsCommandList));
- if (FAILED(res))
- {
- Assert(false && "Error not implemented: cannot create ID3D12GraphicsCommandList6 (graphics or "
- "compute command list");
- return false;
- }
- commandListSlot = reinterpret_cast(d3d12GraphicsCommandList);
- }
- else if (queueType == QueueType::Copy)
- {
- ID3D12GraphicsCommandList* d3d12CopyCommandList = nullptr;
- res = ID3D12Device5_CreateCommandList1(driver->D3D12Device, queueDesc.NodeMask, queueDesc.Type,
- D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList6,
- reinterpret_cast(&d3d12CopyCommandList));
- if (FAILED(res))
- {
- Assert(false &&
- "Error not implemented: cannot create ID3D12GraphicsCommandList (copy command list)");
- return false;
- }
- commandListSlot = reinterpret_cast(d3d12CopyCommandList);
- }
-
+ bool CreateD3D12CommandList(NonNullPtr driver, NonNullPtr commandList, QueueType queueType)
+ {
// TODO: String library
std::wstring wide_str = L"CommandList ID:" + std::to_wstring(commandList->ID);
- ID3D12GraphicsCommandList_SetName(commandListSlot, wide_str.c_str());
- return true;
+ // TODO: Factorize this. Flemme
+ auto& queueDesc = driver->QueueDesc[ToUnderlying(queueType)];
+ switch (queueType)
+ {
+ case QueueType::Graphics:
+ {
+ CreateAllocator(driver, &commandList->GraphicsCommandList, queueDesc);
+ ID3D12GraphicsCommandList6* d3d12GraphicsCommandList = nullptr;
+ HRESULT result =
+ ID3D12Device5_CreateCommandList1(driver->D3D12Device, 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;
+ ID3D12GraphicsCommandList6_SetName(d3d12GraphicsCommandList, wide_str.c_str());
+ return true;
+ }
+ case QueueType::Compute:
+ {
+ CreateAllocator(driver, &commandList->ComputeCommandList, queueDesc);
+ ID3D12GraphicsCommandList6* d3d12GraphicsCommandList = nullptr;
+ HRESULT result =
+ ID3D12Device5_CreateCommandList1(driver->D3D12Device, 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;
+ ID3D12GraphicsCommandList6_SetName(d3d12GraphicsCommandList, wide_str.c_str());
+ return true;
+ }
+ case QueueType::Copy:
+ {
+ CreateAllocator(driver, &commandList->CopyCommandList, queueDesc);
+ ID3D12GraphicsCommandList* d3d12CopyCommandList = nullptr;
+ HRESULT result = ID3D12Device5_CreateCommandList1(driver->D3D12Device, queueDesc.NodeMask, queueDesc.Type,
+ D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList,
+ reinterpret_cast(&d3d12CopyCommandList));
+ if (FAILED(result))
+ {
+ Assert(false &&
+ "Error not implemented: cannot create ID3D12GraphicsCommandList (copy command list)");
+ return false;
+ }
+ commandList->CopyCommandList.CommandList = d3d12CopyCommandList;
+ ID3D12GraphicsCommandList_SetName(d3d12CopyCommandList, wide_str.c_str());
+ return true;
+ }
+ default: return false;
+ }
}
bool AllocateCommandList(NonNullPtr driver, QueueType queueType)
@@ -102,16 +140,11 @@ namespace Juliet::D3D12
}
} // namespace
- ID3D12GraphicsCommandList6* GetGraphicsCommandList(NonNullPtr commandList)
- {
- return reinterpret_cast(commandList->CommandLists[ToUnderlying(QueueType::Graphics)]);
- }
-
CommandList* AcquireCommandList(NonNullPtr driver, QueueType queueType)
{
auto* d3d12Driver = static_cast(driver.Get());
- uint8 currentCommandListIndex = d3d12Driver->CommandListCount;
+ uint8 currentCommandListIndex = d3d12Driver->AvailableCommandListCount;
if (currentCommandListIndex >= d3d12Driver->AvailableCommandListCapacity)
{
if (!AllocateCommandList(d3d12Driver, queueType))
@@ -130,6 +163,35 @@ namespace Juliet::D3D12
}
}
+ // Get Proper allocator for the frame and reset both it and the requested queue
+ uint8 bufferIndex = d3d12Driver->FrameCounter % GPUDriver::kResourceBufferCount;
+ switch (queueType)
+ {
+ case QueueType::Graphics:
+ {
+ auto* allocator = commandList->GraphicsCommandList.Allocator[bufferIndex];
+ ID3D12CommandAllocator_Reset(allocator);
+ ID3D12GraphicsCommandList6_Reset(commandList->GraphicsCommandList.CommandList, allocator, nullptr);
+ break;
+ }
+ case QueueType::Compute:
+ {
+ auto* allocator = commandList->ComputeCommandList.Allocator[bufferIndex];
+ ID3D12CommandAllocator_Reset(allocator);
+ ID3D12GraphicsCommandList6_Reset(commandList->ComputeCommandList.CommandList, allocator, nullptr);
+ break;
+ }
+ case QueueType::Copy:
+ {
+ auto* allocator = commandList->CopyCommandList.Allocator[bufferIndex];
+ ID3D12CommandAllocator_Reset(allocator);
+ ID3D12GraphicsCommandList6_Reset(commandList->CopyCommandList.CommandList, allocator, nullptr);
+ break;
+ }
+ default: Assert(false && "Unsupported QueueType"); return nullptr;
+ }
+
+ d3d12Driver->AvailableCommandListCount += 1;
return reinterpret_cast(commandList);
}
@@ -138,7 +200,7 @@ namespace Juliet::D3D12
auto* d3d12Driver = static_cast(driver.Get());
bool success = true;
- uint8 commandLastIndex = d3d12Driver->CommandListCount;
+ uint8 commandLastIndex = d3d12Driver->AvailableCommandListCount;
// 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);
@@ -147,6 +209,9 @@ namespace Juliet::D3D12
success = false;
}
+ d3d12Driver->AvailableCommandListCount = 0;
+ ++d3d12Driver->FrameCounter;
+
return success;
}
diff --git a/Juliet/src/Graphics/D3D12/DX12CommandList.h b/Juliet/src/Graphics/D3D12/DX12CommandList.h
index f794c00..4ae90ef 100644
--- a/Juliet/src/Graphics/D3D12/DX12CommandList.h
+++ b/Juliet/src/Graphics/D3D12/DX12CommandList.h
@@ -7,13 +7,29 @@
namespace Juliet::D3D12
{
+ // Forward Declare
struct D3D12Driver;
struct D3D12WindowData;
+ struct D3D12CommandListBaseData
+ {
+ ID3D12CommandAllocator* Allocator[GPUDriver::kResourceBufferCount];
+ };
+
+ struct D3D12CopyCommandListData : D3D12CommandListBaseData
+ {
+ ID3D12GraphicsCommandList* CommandList;
+ };
+
+ struct D3D12GraphicsCommandListData : D3D12CommandListBaseData
+ {
+ ID3D12GraphicsCommandList6* CommandList;
+ };
+
struct D3D12PresentData
{
D3D12WindowData* WindowData;
- uint32 SwapChainImageIndex;
+ uint32 SwapChainImageIndex;
};
struct D3D12CommandList
@@ -24,16 +40,14 @@ namespace Juliet::D3D12
D3D12Driver* Driver;
D3D12PresentData* PresentDatas;
- uint32 PresentDataCapacity;
- uint32 PresentDataCount;
+ uint32 PresentDataCapacity;
+ uint32 PresentDataCount;
- // We create kResourceBufferCount allocator per queue to allow reusing the command list every N frames
- ID3D12CommandAllocator* CommandAllocator[GPUDriver::kResourceBufferCount][ToUnderlying(QueueType::Count)];
- ID3D12CommandList* CommandLists[ToUnderlying(QueueType::Count)];
+ D3D12GraphicsCommandListData GraphicsCommandList;
+ D3D12GraphicsCommandListData ComputeCommandList;
+ D3D12CopyCommandListData CopyCommandList;
};
- ID3D12GraphicsCommandList6* GetGraphicsCommandList(NonNullPtr commandList);
-
extern CommandList* AcquireCommandList(NonNullPtr driver, QueueType queueType);
extern bool SubmitCommandLists(NonNullPtr driver);
} // namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp
index 63bdcf0..eca3fb8 100644
--- a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp
+++ b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp
@@ -3,6 +3,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -549,6 +550,8 @@ namespace Juliet::D3D12
device->AcquireCommandList = AcquireCommandList;
device->SubmitCommandLists = SubmitCommandLists;
+ device->BeginRenderPass = BeginRenderPass;
+
device->Driver = driver;
driver->GraphicsDevice = device;
diff --git a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h
index d9923bb..8a2b3d2 100644
--- a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h
+++ b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h
@@ -12,6 +12,7 @@ namespace Juliet
namespace Juliet::D3D12
{
+ // Forward Declare
struct D3D12CommandList;
struct D3D12WindowData
@@ -26,7 +27,7 @@ namespace Juliet::D3D12
PresentMode PresentMode;
- uint32 FrameCounter;
+ uint32 WindowFrameCounter; // Specific to that window. See GraphicsDevice for global counter
uint32 Width;
uint32 Height;
};
@@ -63,10 +64,12 @@ namespace Juliet::D3D12
// Resources
D3D12CommandList** AvailableCommandLists;
uint8 AvailableCommandListCapacity;
+ uint8 AvailableCommandListCount;
D3D12StagingDescriptorPool* StagingDescriptorPools[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES];
uint8 FramesInFlight;
+ uint64 FrameCounter = 0; // Number of frame since inception
bool IsTearingSupported : 1;
bool IsUMAAvailable : 1;
diff --git a/Juliet/src/Graphics/D3D12/DX12Includes.h b/Juliet/src/Graphics/D3D12/DX12Includes.h
index 8902c69..e895801 100644
--- a/Juliet/src/Graphics/D3D12/DX12Includes.h
+++ b/Juliet/src/Graphics/D3D12/DX12Includes.h
@@ -26,3 +26,6 @@
#ifdef __IDXGIInfoQueue_INTERFACE_DEFINED__
#define IDXGIINFOQUEUE_SUPPORTED
#endif
+
+#undef min
+#undef max
diff --git a/Juliet/src/Graphics/D3D12/DX12SwapChain.cpp b/Juliet/src/Graphics/D3D12/DX12SwapChain.cpp
index 255f604..4172d73 100644
--- a/Juliet/src/Graphics/D3D12/DX12SwapChain.cpp
+++ b/Juliet/src/Graphics/D3D12/DX12SwapChain.cpp
@@ -162,11 +162,10 @@ namespace Juliet::D3D12
if (d3d12CommandList->PresentDataCount == d3d12CommandList->PresentDataCapacity)
{
d3d12CommandList->PresentDataCapacity += 1;
- d3d12CommandList->PresentDatas =
- static_cast(Realloc(d3d12CommandList->PresentDatas,
- d3d12CommandList->PresentDataCapacity * sizeof(D3D12PresentData)));
+ d3d12CommandList->PresentDatas = static_cast(
+ Realloc(d3d12CommandList->PresentDatas, d3d12CommandList->PresentDataCapacity * sizeof(D3D12PresentData)));
}
- d3d12CommandList->PresentDatas[d3d12CommandList->PresentDataCount].WindowData = windowData;
+ d3d12CommandList->PresentDatas[d3d12CommandList->PresentDataCount].WindowData = windowData;
d3d12CommandList->PresentDatas[d3d12CommandList->PresentDataCount].SwapChainImageIndex = swapchainIndex;
d3d12CommandList->PresentDataCount += 1;
@@ -179,7 +178,7 @@ namespace Juliet::D3D12
barrierDesc.Transition.pResource = windowData->SwapChainTextureContainers[swapchainIndex].ActiveTexture->Resource;
barrierDesc.Transition.Subresource = 0;
- ID3D12GraphicsCommandList_ResourceBarrier(GetGraphicsCommandList(d3d12CommandList), 1, &barrierDesc);
+ ID3D12GraphicsCommandList_ResourceBarrier(d3d12CommandList->GraphicsCommandList.CommandList, 1, &barrierDesc);
*swapchainTexture = reinterpret_cast(&windowData->SwapChainTextureContainers[swapchainIndex]);
@@ -281,7 +280,7 @@ namespace Juliet::D3D12
windowData->SwapChain = swapChain3;
windowData->SwapChainColorSpace = SwapchainCompositionToColorSpace[ToUnderlying(composition)];
windowData->SwapChainComposition = composition;
- windowData->FrameCounter = 0;
+ windowData->WindowFrameCounter = 0;
windowData->Width = swapChainDesc.Width;
windowData->Height = swapChainDesc.Height;
windowData->PresentMode = presentMode;
diff --git a/Juliet/src/Graphics/D3D12/DX12SwapChain.h b/Juliet/src/Graphics/D3D12/DX12SwapChain.h
index de08684..b7a7aef 100644
--- a/Juliet/src/Graphics/D3D12/DX12SwapChain.h
+++ b/Juliet/src/Graphics/D3D12/DX12SwapChain.h
@@ -3,6 +3,7 @@
namespace Juliet::D3D12
{
+ // Forward Declare
struct D3D12Driver;
struct D3D12WindowData;
diff --git a/Juliet/src/Graphics/D3D12/DX12Utils.cpp b/Juliet/src/Graphics/D3D12/DX12Utils.cpp
index b6e4380..b3a9123 100644
--- a/Juliet/src/Graphics/D3D12/DX12Utils.cpp
+++ b/Juliet/src/Graphics/D3D12/DX12Utils.cpp
@@ -38,7 +38,7 @@ namespace Juliet::D3D12
}
// Ensure valid range
- dwChars = std::min(dwChars, MAX_ERROR_LEN);
+ dwChars = Min(dwChars, MAX_ERROR_LEN);
// Trim whitespace from tail of message
while (dwChars > 0)
diff --git a/Juliet/src/Graphics/Graphics.cpp b/Juliet/src/Graphics/Graphics.cpp
index ee8bcbc..7ba48c6 100644
--- a/Juliet/src/Graphics/Graphics.cpp
+++ b/Juliet/src/Graphics/Graphics.cpp
@@ -65,9 +65,7 @@ namespace Juliet
bool AttachToWindow(NonNullPtr device, NonNullPtr window)
{
GPUDriver* driver = device->Driver;
- bool result = device->AttachToWindow(driver, window);
-
- return result;
+ return device->AttachToWindow(driver, window);
}
void DetachFromWindow(NonNullPtr device, NonNullPtr window)
@@ -93,16 +91,14 @@ namespace Juliet
{
GPUDriver* driver = device->Driver;
CommandList* cmdList = device->AcquireCommandList(driver, queueType);
-
if (!cmdList)
{
return nullptr;
}
- auto header = reinterpret_cast(cmdList);
- header->Device = device.Get();
-
- driver->CommandListCount += 1;
+ auto header = reinterpret_cast(cmdList);
+ header->Device = device.Get();
+ header->RenderPass.CommandList = cmdList;
return cmdList;
}
@@ -111,8 +107,27 @@ namespace Juliet
{
GPUDriver* driver = device->Driver;
device->SubmitCommandLists(driver);
+ }
- driver->CommandListCount = 0;
+ RenderPass* BeginRenderPass(NonNullPtr commandList, ColorTargetInfo& colorTargetInfo)
+ {
+ return BeginRenderPass(commandList, &colorTargetInfo, 1);
+ }
+
+ RenderPass* BeginRenderPass(NonNullPtr commandList, NonNullPtr colorTargetInfos,
+ uint32 colorTargetInfoCount)
+ {
+ 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);
+
+ header->RenderPass.IsInProgress = true;
+ return reinterpret_cast(&header->RenderPass);
}
} // namespace Juliet
diff --git a/Juliet/src/Graphics/GraphicsDevice.h b/Juliet/src/Graphics/GraphicsDevice.h
index ab04c05..9a5ff3a 100644
--- a/Juliet/src/Graphics/GraphicsDevice.h
+++ b/Juliet/src/Graphics/GraphicsDevice.h
@@ -7,25 +7,30 @@
namespace Juliet
{
- struct Window;
-
struct TextureHeader
{
TextureCreateInfo CreateInfo;
};
+ struct GPUPass
+ {
+ CommandList* CommandList;
+ bool IsInProgress : 1;
+ };
+
struct CommandListHeader
{
GraphicsDevice* Device = nullptr;
bool AcquiredSwapChain = false;
+
+ GPUPass RenderPass;
};
struct GPUDriver
{
- uint8 CommandListCount;
-
static constexpr uint8 kResourceBufferCount = 2;
static constexpr uint8 kMaxFramesInFlight = 3;
+ static constexpr uint8 kMaxColorTargetInfo = 4;
};
struct GraphicsDevice
@@ -43,6 +48,10 @@ namespace Juliet
CommandList* (*AcquireCommandList)(NonNullPtr driver, QueueType queueType);
bool (*SubmitCommandLists)(NonNullPtr driver);
+ // RenderPass
+ void (*BeginRenderPass)(NonNullPtr commandList, NonNullPtr colorTargetInfos,
+ uint32 colorTargetInfoCount);
+
const char* Name = "Unknown";
GPUDriver* Driver = nullptr;
};
diff --git a/Juliet/src/TODO.txt b/Juliet/src/TODO.txt
index f585166..5f914c3 100644
--- a/Juliet/src/TODO.txt
+++ b/Juliet/src/TODO.txt
@@ -1 +1,3 @@
+Rename DX12 files to D3D12
+
- Create Simple vector class to make the vector stuff a bit more easier than writing Capacity and Count
\ No newline at end of file
diff --git a/JulietApp/Editor/EditorMain_win32.cpp b/JulietApp/Editor/EditorMain_win32.cpp
index e332fd5..be8ac9a 100644
--- a/JulietApp/Editor/EditorMain_win32.cpp
+++ b/JulietApp/Editor/EditorMain_win32.cpp
@@ -13,6 +13,7 @@
// TODO : Replace with message box from framework + call main and not winmain + subsystem
#include
#include
+#include
#include
// TODO : Think how to do the draw pipeline.
@@ -97,6 +98,17 @@ void Win32EditorApplication::Update()
return;
}
+ if (swapChainTexture)
+ {
+ ColorTargetInfo colorTargetInfo = {};
+ colorTargetInfo.Texture = swapChainTexture;
+ colorTargetInfo.ClearColor = { .R = .5f, .G = .8f, .B = .0f, .A = 1.f };
+ colorTargetInfo.LoadOperation = LoadOperation::Clear;
+ colorTargetInfo.StoreOperation = StoreOperation::Store;
+
+ BeginRenderPass(cmdList, colorTargetInfo);
+ }
+
// Submit Commands
SubmitCommandLists(GraphicsDevice);
}
diff --git a/JulietApp/Editor/EditorMain_win32.h b/JulietApp/Editor/EditorMain_win32.h
index 7a8c8a6..444e586 100644
--- a/JulietApp/Editor/EditorMain_win32.h
+++ b/JulietApp/Editor/EditorMain_win32.h
@@ -21,7 +21,7 @@ class Win32EditorApplication : public Juliet::IApplication
private:
Juliet::Window* MainWindow = {};
Juliet::GraphicsDevice* GraphicsDevice = {};
- Juliet::DynamicLibrary* Game = {};
+ Juliet::DynamicLibrary* Game = {};
bool Running = false;
};