Compare commits

...

6 Commits

Author SHA1 Message Date
8326772558 Finishing fences
+ moved some functions to an internal namespace to tidy stuff a bit
2025-02-19 22:01:39 -05:00
cc9bbf0ef5 Fences first pass 2025-02-18 22:26:50 -05:00
857f8c4e69 Command list Submit done. 2025-02-18 21:52:49 -05:00
ed9482b8f8 End Render pass 2025-02-18 21:12:36 -05:00
f1b7f8eb29 Finished first pass BeginRenderPass. 2025-02-18 20:23:12 -05:00
ee194b2d69 Renderpass first iteration 2025-02-17 22:08:53 -05:00
30 changed files with 1751 additions and 437 deletions

View File

@@ -123,46 +123,51 @@
<ClInclude Include="include\Core\JulietInit.h"/>
<ClInclude Include="include\Core\Logging\LogManager.h"/>
<ClInclude Include="include\Core\Logging\LogTypes.h"/>
<ClInclude Include="include\Core\Memory\Allocator.h"/>
<ClInclude Include="include\Core\Memory\Utils.h"/>
<ClInclude Include="include\Core\Networking\IPAddress.h"/>
<ClInclude Include="include\Core\Networking\NetworkPacket.h"/>
<ClInclude Include="include\Core\Networking\Socket.h"/>
<ClInclude Include="include\Core\Networking\SocketHandle.h"/>
<ClInclude Include="include\Core\Networking\TcpListener.h"/>
<ClInclude Include="include\Core\Networking\TcpSocket.h"/>
<ClInclude Include="include\Core\Thread\Thread.h"/>
<ClInclude Include="include\Engine\Class.h"/>
<ClInclude Include="include\Engine\Engine.h"/>
<ClInclude Include="include\Graphics\Graphics.h"/>
<ClInclude Include="include\Graphics\GraphicsConfig.h"/>
<ClInclude Include="include\Core\Math\Shape.h" />
<ClInclude Include="include\Core\Memory\Allocator.h" />
<ClInclude Include="include\Core\Memory\Utils.h" />
<ClInclude Include="include\Core\Networking\IPAddress.h" />
<ClInclude Include="include\Core\Networking\NetworkPacket.h" />
<ClInclude Include="include\Core\Networking\Socket.h" />
<ClInclude Include="include\Core\Networking\SocketHandle.h" />
<ClInclude Include="include\Core\Networking\TcpListener.h" />
<ClInclude Include="include\Core\Networking\TcpSocket.h" />
<ClInclude Include="include\Core\Thread\Thread.h" />
<ClInclude Include="include\Engine\Class.h" />
<ClInclude Include="include\Engine\Engine.h" />
<ClInclude Include="include\Graphics\Colors.h" />
<ClInclude Include="include\Graphics\Graphics.h" />
<ClInclude Include="include\Graphics\GraphicsConfig.h" />
<ClInclude Include="include\Graphics\RenderPass.h" />
<ClInclude Include="include\Graphics\Texture.h" />
<ClInclude Include="include\Juliet.h"/>
<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\Win32DisplayEvent.h"/>
<ClInclude Include="src\Core\HAL\Display\Win32\Win32Window.h"/>
<ClInclude Include="src\Core\HAL\Display\Window.h"/>
<ClInclude Include="src\Core\HAL\Event\KeyboardMapping.h"/>
<ClInclude Include="src\Core\HAL\Event\Keyboard_Private.h"/>
<ClInclude Include="src\Core\HAL\Event\Mouse_Private.h"/>
<ClInclude Include="src\Core\HAL\Event\Win32ScanCode.h"/>
<ClInclude Include="src\Core\HAL\Event\WindowEvent.h"/>
<ClInclude Include="src\Core\Networking\SocketPlatformImpl.h"/>
<ClInclude Include="src\Core\HAL\Win32.h"/>
<ClInclude Include="include\Juliet.h" />
<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\Win32DisplayEvent.h" />
<ClInclude Include="src\Core\HAL\Display\Win32\Win32Window.h" />
<ClInclude Include="src\Core\HAL\Display\Window.h" />
<ClInclude Include="src\Core\HAL\Event\KeyboardMapping.h" />
<ClInclude Include="src\Core\HAL\Event\Keyboard_Private.h" />
<ClInclude Include="src\Core\HAL\Event\Mouse_Private.h" />
<ClInclude Include="src\Core\HAL\Event\Win32ScanCode.h" />
<ClInclude Include="src\Core\HAL\Event\WindowEvent.h" />
<ClInclude Include="src\Core\Networking\SocketPlatformImpl.h" />
<ClInclude Include="src\Core\HAL\Win32.h" />
<ClInclude Include="src\Graphics\D3D12\D3D12Common.h" />
<ClInclude Include="src\Graphics\D3D12\D3D12RenderPass.h" />
<ClInclude Include="src\Graphics\D3D12\D3D12Synchronization.h" />
<ClInclude Include="src\Graphics\D3D12\D3D12Texture.h" />
<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"/>
<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>
<ItemGroup>
<ClCompile Include="src\Core\Application\ApplicationManager.cpp"/>
<ClCompile Include="src\Core\Common\CoreUtils.cpp"/>
<ClCompile Include="src\Core\Application\ApplicationManager.cpp" />
<ClCompile Include="src\Core\Common\CoreUtils.cpp" />
<ClCompile Include="src\Core\DynLib\Win32\DynamicLibrary.cpp">
<RuntimeLibrary>MultiThreadedDebugDll</RuntimeLibrary>
<Optimization>Disabled</Optimization>
@@ -217,29 +222,31 @@
<MSCVersion>Default</MSCVersion>
<AdditionalOptions>--target=amd64-pc-windows-msvc</AdditionalOptions>
</ClCompile>
<ClCompile Include="src\Core\HAL\Display\Display.cpp"/>
<ClCompile Include="src\Core\HAL\Display\Win32\Win32DisplayDevice.cpp"/>
<ClCompile Include="src\Core\HAL\Display\Win32\Win32DisplayEvent.cpp"/>
<ClCompile Include="src\Core\HAL\Display\Win32\Win32Window.cpp"/>
<ClCompile Include="src\Core\HAL\Event\Keyboard.cpp"/>
<ClCompile Include="src\Core\HAL\Event\KeyboardMapping.cpp"/>
<ClCompile Include="src\Core\HAL\Event\Mouse.cpp"/>
<ClCompile Include="src\Core\HAL\Event\SystemEvent.cpp"/>
<ClCompile Include="src\Core\HAL\Event\WindowEvent.cpp"/>
<ClCompile Include="src\Core\Juliet.cpp"/>
<ClCompile Include="src\Core\Logging\LogManager.cpp"/>
<ClCompile Include="src\Core\Memory\Allocator.cpp"/>
<ClCompile Include="src\Core\Networking\NetworkPacket.cpp"/>
<ClCompile Include="src\Core\Networking\Socket.cpp"/>
<ClCompile Include="src\Core\Networking\TcpListener.cpp"/>
<ClCompile Include="src\Core\Networking\TcpSocket.cpp"/>
<ClCompile Include="src\Core\Networking\Win32\Win32SocketPlatformImpl.cpp"/>
<ClCompile Include="src\Engine\Engine.cpp"/>
<ClCompile Include="src\Core\HAL\Display\Display.cpp" />
<ClCompile Include="src\Core\HAL\Display\Win32\Win32DisplayDevice.cpp" />
<ClCompile Include="src\Core\HAL\Display\Win32\Win32DisplayEvent.cpp" />
<ClCompile Include="src\Core\HAL\Display\Win32\Win32Window.cpp" />
<ClCompile Include="src\Core\HAL\Event\Keyboard.cpp" />
<ClCompile Include="src\Core\HAL\Event\KeyboardMapping.cpp" />
<ClCompile Include="src\Core\HAL\Event\Mouse.cpp" />
<ClCompile Include="src\Core\HAL\Event\SystemEvent.cpp" />
<ClCompile Include="src\Core\HAL\Event\WindowEvent.cpp" />
<ClCompile Include="src\Core\Juliet.cpp" />
<ClCompile Include="src\Core\Logging\LogManager.cpp" />
<ClCompile Include="src\Core\Memory\Allocator.cpp" />
<ClCompile Include="src\Core\Networking\NetworkPacket.cpp" />
<ClCompile Include="src\Core\Networking\Socket.cpp" />
<ClCompile Include="src\Core\Networking\TcpListener.cpp" />
<ClCompile Include="src\Core\Networking\TcpSocket.cpp" />
<ClCompile Include="src\Core\Networking\Win32\Win32SocketPlatformImpl.cpp" />
<ClCompile Include="src\Engine\Engine.cpp" />
<ClCompile Include="src\Graphics\D3D12\D3D12Common.cpp" />
<ClCompile Include="src\Graphics\D3D12\D3D12RenderPass.cpp" />
<ClCompile Include="src\Graphics\D3D12\D3D12Synchronization.cpp" />
<ClCompile Include="src\Graphics\D3D12\D3D12Texture.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\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>
@@ -301,7 +308,7 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<Content Include="include\Core\Thread\Mutex.h"/>
<Content Include="include\Core\Thread\Mutex.h" />
<Content Include="src\TODO.txt" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/>

View File

@@ -2,6 +2,7 @@
#include <cstddef>
#include <cstdint>
#include <limits>
using uint8 = uint8_t;
using uint16 = uint16_t;
@@ -24,3 +25,14 @@ struct ByteBuffer
};
using FunctionPtr = auto (*)(void) -> void;
// Limits
template <typename Type>
consteval Type MaxValueOf()
{
return std::numeric_limits<Type>::max();
}
constexpr uint32 uint8Max = MaxValueOf<uint8>();
constexpr uint32 uint16Max = MaxValueOf<uint16>();
constexpr uint32 uint32Max = MaxValueOf<uint32>();
constexpr uint32 uint64Max = MaxValueOf<uint64>();

View File

@@ -1,5 +1,6 @@
#pragma once
#include <algorithm>
#include <Core/Common/CoreTypes.h>
#include <Juliet.h>
@@ -24,7 +25,8 @@ namespace Juliet
extern void JULIET_API JulietAssert(const char* expression);
#define ZeroStruct(structInstance) ZeroSize(sizeof(structInstance), &(structInstance))
#define ZeroArray(Count, Pointer) ZeroSize((Count) * sizeof((Pointer)[0]), Pointer)
#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)
{
auto Byte = (uint8*)ptr;
@@ -35,4 +37,30 @@ namespace Juliet
}
#define MemCopy memcpy
template <typename Type>
constexpr Type Min(Type lhs, Type rhs)
{
return rhs < lhs ? rhs : lhs;
}
template <typename Type>
constexpr Type Max(Type lhs, Type rhs)
{
return lhs < rhs ? rhs : lhs;
}
template <typename Type>
constexpr Type Clamp(Type val, Type min, Type max)
{
if (val < min)
{
return min;
}
if (val > max)
{
return max;
}
return val;
}
} // namespace Juliet

View File

@@ -0,0 +1,12 @@
#pragma once
namespace Juliet
{
struct Rectangle
{
int32 X;
int32 Y;
int32 Width;
int32 Height;
};
}

View File

@@ -0,0 +1,16 @@
#pragma once
namespace Juliet
{
template <typename Type>
struct ColorType
{
Type R;
Type G;
Type B;
Type A;
};
using FColor = ColorType<float>;
using Color = ColorType<uint8>;
} // namespace Juliet

View File

@@ -1,15 +1,19 @@
#pragma once
#include <core/Common/NonNullPtr.h>
#include <Core/Common/NonNullPtr.h>
#include <Core/HAL/Display/Display.h>
#include <Core/Math/Shape.h>
#include <Graphics/GraphicsConfig.h>
#include <Graphics/Texture.h>
#include <Graphics/RenderPass.h>
#include <Juliet.h>
// Graphics Interface
namespace Juliet
{
struct Window;
// Opaque types
struct CommandList;
struct GraphicsDevice;
struct Fence;
// Parameters of an indirect draw command
struct IndirectDrawCommand
@@ -65,8 +69,15 @@ namespace Juliet
Immediate
};
// Opaque types
struct CommandList;
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<GraphicsDevice> device);
@@ -81,5 +92,16 @@ namespace Juliet
// Command List
extern JULIET_API CommandList* AcquireCommandList(NonNullPtr<GraphicsDevice> device, QueueType queueType = QueueType::Graphics);
extern JULIET_API void SubmitCommandLists(NonNullPtr<GraphicsDevice> device);
extern JULIET_API void SubmitCommandLists(NonNullPtr<CommandList> commandList);
// RenderPass
extern JULIET_API RenderPass* BeginRenderPass(NonNullPtr<CommandList> commandList, ColorTargetInfo& colorTargetInfo);
extern JULIET_API RenderPass* BeginRenderPass(NonNullPtr<CommandList> commandList,
NonNullPtr<const ColorTargetInfo> colorTargetInfos, uint32 colorTargetInfoCount);
extern JULIET_API void EndRenderPass(NonNullPtr<RenderPass> renderPass);
extern JULIET_API void SetGraphicsViewPort(NonNullPtr<RenderPass> renderPass, const GraphicsViewPort& viewPort);
extern JULIET_API void SetScissorRect(NonNullPtr<RenderPass> renderPass, const Rectangle& rectangle);
extern JULIET_API void SetBlendConstants(NonNullPtr<RenderPass> renderPass, FColor blendConstants);
extern JULIET_API void SetStencilReference(NonNullPtr<RenderPass> renderPass, uint8 reference);
} // namespace Juliet

View File

@@ -0,0 +1,46 @@
#pragma once
#include <Graphics/Colors.h>
#include <Graphics/Texture.h>
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* TargetTexture;
uint32 MipLevel;
union
{
uint32 DepthPlane;
uint32 LayerIndex;
};
bool CycleTexture; // Whether the texture should be cycled if already bound (and load operation != LOAD)
Texture* ResolveTexture;
uint32 ResolveMipLevel;
uint32 ResolveLayerIndex;
bool CycleResolveTexture;
FColor ClearColor;
LoadOperation LoadOperation;
StoreOperation StoreOperation;
};
// Opaque Type
struct RenderPass;
} // namespace Juliet

View File

@@ -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

View File

@@ -58,3 +58,6 @@
#define ANSI_ONLY
#include <Windows.h>
#undef min
#undef max

View File

@@ -26,7 +26,7 @@ namespace Juliet::D3D12
bool ExtendStagingDescriptorPool(NonNullPtr<D3D12Driver> driver, D3D12StagingDescriptorPool& pool)
{
D3D12DescriptorHeap* heap =
CreateDescriptorHeap(driver, pool.Heaps[0]->HeapType, kStagingHeapDescriptorExpectedCount, true);
Internal::CreateDescriptorHeap(driver, pool.Heaps[0]->HeapType, kStagingHeapDescriptorExpectedCount, true);
if (!heap)
{
return false;
@@ -47,122 +47,126 @@ namespace Juliet::D3D12
}
} // namespace
D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count, bool isStaging)
namespace Internal
{
ID3D12DescriptorHeap* handle;
auto heap = static_cast<D3D12DescriptorHeap*>(Calloc(1, sizeof(D3D12DescriptorHeap)));
if (!heap)
D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type,
uint32 count, bool isStaging)
{
return nullptr;
}
ID3D12DescriptorHeap* handle;
heap->CurrentDescriptorIndex = 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;
HRESULT result =
ID3D12Device_CreateDescriptorHeap(driver->D3D12Device, &heapDesc, IID_ID3D12DescriptorHeap, (void**)&handle);
if (FAILED(result))
{
LogError(driver, "Failed to create descriptor heap!", result);
DestroyDescriptorHeap(heap);
return nullptr;
}
heap->Handle = handle;
heap->HeapType = type;
heap->MaxDescriptors = count;
heap->Staging = isStaging;
heap->DescriptorSize = ID3D12Device_GetDescriptorHandleIncrementSize(driver->D3D12Device, type);
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(handle, &heap->DescriptorHeapCPUStart);
if (!isStaging)
{
ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(handle, &heap->DescriptorHeapGPUStart);
}
return heap;
}
void DestroyDescriptorHeap(NonNullPtr<D3D12DescriptorHeap> heap)
{
if (heap->Handle)
{
ID3D12DescriptorHeap_Release(heap->Handle);
}
Free(heap.Get());
}
D3D12StagingDescriptorPool* CreateStagingDescriptorPool(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type)
{
D3D12DescriptorHeap* heap = CreateDescriptorHeap(driver, type, kStagingHeapDescriptorExpectedCount, true);
if (!heap)
{
return nullptr;
}
auto pool = static_cast<D3D12StagingDescriptorPool*>(Calloc(1, sizeof(D3D12StagingDescriptorPool)));
// First create the heaps
pool->HeapCount = 1;
pool->Heaps = static_cast<D3D12DescriptorHeap**>(Malloc(sizeof(D3D12DescriptorHeap*)));
pool->Heaps[0] = heap;
pool->FreeDescriptorCapacity = kStagingHeapDescriptorExpectedCount;
pool->FreeDescriptorCount = kStagingHeapDescriptorExpectedCount;
pool->FreeDescriptors =
static_cast<D3D12StagingDescriptor*>(Malloc(kStagingHeapDescriptorExpectedCount * sizeof(D3D12StagingDescriptor)));
InitStagingDescriptorPool(heap, pool);
return pool;
}
bool AssignStagingDescriptor(NonNullPtr<D3D12Driver> 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))
auto heap = static_cast<D3D12DescriptorHeap*>(Calloc(1, sizeof(D3D12DescriptorHeap)));
if (!heap)
{
return false;
return nullptr;
}
heap->CurrentDescriptorIndex = 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;
HRESULT result =
ID3D12Device_CreateDescriptorHeap(driver->D3D12Device, &heapDesc, IID_ID3D12DescriptorHeap, (void**)&handle);
if (FAILED(result))
{
LogError(driver, "Failed to create descriptor heap!", result);
DestroyDescriptorHeap(heap);
return nullptr;
}
heap->Handle = handle;
heap->HeapType = type;
heap->MaxDescriptors = count;
heap->Staging = isStaging;
heap->DescriptorSize = ID3D12Device_GetDescriptorHandleIncrementSize(driver->D3D12Device, type);
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(handle, &heap->DescriptorHeapCPUStart);
if (!isStaging)
{
ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(handle, &heap->DescriptorHeapGPUStart);
}
return heap;
}
void DestroyDescriptorHeap(NonNullPtr<D3D12DescriptorHeap> heap)
{
if (heap->Handle)
{
ID3D12DescriptorHeap_Release(heap->Handle);
}
Free(heap.Get());
}
D3D12StagingDescriptorPool* CreateStagingDescriptorPool(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type)
{
D3D12DescriptorHeap* heap = CreateDescriptorHeap(driver, type, kStagingHeapDescriptorExpectedCount, true);
if (!heap)
{
return nullptr;
}
auto pool = static_cast<D3D12StagingDescriptorPool*>(Calloc(1, sizeof(D3D12StagingDescriptorPool)));
// First create the heaps
pool->HeapCount = 1;
pool->Heaps = static_cast<D3D12DescriptorHeap**>(Malloc(sizeof(D3D12DescriptorHeap*)));
pool->Heaps[0] = heap;
pool->FreeDescriptorCapacity = kStagingHeapDescriptorExpectedCount;
pool->FreeDescriptorCount = kStagingHeapDescriptorExpectedCount;
pool->FreeDescriptors = static_cast<D3D12StagingDescriptor*>(
Malloc(kStagingHeapDescriptorExpectedCount * sizeof(D3D12StagingDescriptor)));
InitStagingDescriptorPool(heap, pool);
return pool;
}
bool AssignStagingDescriptor(NonNullPtr<D3D12Driver> 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;
}
}
descriptor = &pool->FreeDescriptors[pool->FreeDescriptorCount - 1];
MemCopy(&outDescriptor, descriptor, sizeof(D3D12StagingDescriptor));
pool->FreeDescriptorCount -= 1;
return true;
}
void ReleaseStagingDescriptor(NonNullPtr<D3D12Driver> driver, D3D12StagingDescriptor& cpuDescriptor)
{
D3D12StagingDescriptorPool* pool = cpuDescriptor.Pool;
if (pool != nullptr)
{
MemCopy(&pool->FreeDescriptors[pool->FreeDescriptorCount], &cpuDescriptor, sizeof(D3D12StagingDescriptor));
pool->FreeDescriptorCount += 1;
}
}
descriptor = &pool->FreeDescriptors[pool->FreeDescriptorCount - 1];
MemCopy(&outDescriptor, descriptor, sizeof(D3D12StagingDescriptor));
pool->FreeDescriptorCount -= 1;
return true;
}
void ReleaseStagingDescriptor(NonNullPtr<D3D12Driver> driver, D3D12StagingDescriptor& cpuDescriptor)
{
D3D12StagingDescriptorPool* pool = cpuDescriptor.Pool;
if (pool != nullptr)
void DestroyStagingDescriptorPool(NonNullPtr<D3D12StagingDescriptorPool> pool)
{
MemCopy(&pool->FreeDescriptors[pool->FreeDescriptorCount], &cpuDescriptor, sizeof(D3D12StagingDescriptor));
pool->FreeDescriptorCount += 1;
}
}
for (uint32 i = 0; i < pool->HeapCount; i += 1)
{
DestroyDescriptorHeap(pool->Heaps[i]);
}
void DestroyStagingDescriptorPool(NonNullPtr<D3D12StagingDescriptorPool> pool)
{
for (uint32 i = 0; i < pool->HeapCount; i += 1)
{
DestroyDescriptorHeap(pool->Heaps[i]);
Free(pool->Heaps);
Free(pool->FreeDescriptors);
Free(pool.Get());
}
Free(pool->Heaps);
Free(pool->FreeDescriptors);
Free(pool.Get());
}
} // namespace Internal
} // namespace Juliet::D3D12

View File

@@ -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
@@ -51,13 +51,16 @@ namespace Juliet::D3D12
uint32 CpuHandleIndex;
};
extern D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type,
uint32 count, bool isStaging);
extern void DestroyDescriptorHeap(NonNullPtr<D3D12DescriptorHeap> heap);
namespace Internal
{
extern D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr<D3D12Driver> driver,
D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count, bool isStaging);
extern void DestroyDescriptorHeap(NonNullPtr<D3D12DescriptorHeap> heap);
extern D3D12StagingDescriptorPool* CreateStagingDescriptorPool(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type);
extern bool AssignStagingDescriptor(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type,
D3D12StagingDescriptor& outDescriptor);
extern void ReleaseStagingDescriptor(NonNullPtr<D3D12Driver> driver, D3D12StagingDescriptor& cpuDescriptor);
extern void DestroyStagingDescriptorPool(NonNullPtr<D3D12StagingDescriptorPool> pool);
extern D3D12StagingDescriptorPool* CreateStagingDescriptorPool(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type);
extern bool AssignStagingDescriptor(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type,
D3D12StagingDescriptor& outDescriptor);
extern void ReleaseStagingDescriptor(NonNullPtr<D3D12Driver> driver, D3D12StagingDescriptor& cpuDescriptor);
extern void DestroyStagingDescriptorPool(NonNullPtr<D3D12StagingDescriptorPool> pool);
} // namespace Internal
} // namespace Juliet::D3D12

View File

@@ -0,0 +1,160 @@
#include <pch.h>
#include <Graphics/D3D12/D3D12RenderPass.h>
#include <Graphics/D3D12/D3D12Texture.h>
#include <algorithm>
namespace Juliet::D3D12
{
void BeginRenderPass(NonNullPtr<CommandList> commandList, NonNullPtr<const ColorTargetInfo> colorTargetInfos, uint32 colorTargetInfoCount)
{
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
uint32 frameBufferWidth = uint32Max;
uint32 frameBufferHeight = uint32Max;
for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx)
{
auto* container = reinterpret_cast<D3D12TextureContainer*>(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);
}
// TODO : Depth Stencil and DSV
D3D12_CPU_DESCRIPTOR_HANDLE RTVs[GPUDriver::kMaxColorTargetInfo];
for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx)
{
auto* container = reinterpret_cast<D3D12TextureContainer*>(colorTargetInfos[idx].TargetTexture);
D3D12TextureSubresource* subresource = Internal::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;
ID3D12GraphicsCommandList6_ClearRenderTargetView(d3d12CommandList->GraphicsCommandList.CommandList, rtv,
clearColor, 0, nullptr);
}
RTVs[idx] = rtv;
d3d12CommandList->ColorTargetSubresources[idx] = subresource;
// TODO: TrackTexture
if (colorTargetInfos[idx].StoreOperation == StoreOperation::Resolve ||
colorTargetInfos[idx].StoreOperation == StoreOperation::ResolveAndStore)
{
auto resolveContainer = reinterpret_cast<D3D12TextureContainer*>(colorTargetInfos[idx].ResolveTexture);
D3D12TextureSubresource* resolveSubresource =
Internal::PrepareTextureSubresourceForWrite(d3d12CommandList, resolveContainer,
colorTargetInfos[idx].ResolveLayerIndex,
colorTargetInfos[idx].ResolveMipLevel,
colorTargetInfos[idx].CycleResolveTexture,
D3D12_RESOURCE_STATE_RESOLVE_DEST);
d3d12CommandList->ColorResolveSubresources[idx] = resolveSubresource;
// TODO: TrackTexture Resolve
}
}
// TODO DSV
ID3D12GraphicsCommandList_OMSetRenderTargets(d3d12CommandList->GraphicsCommandList.CommandList,
colorTargetInfoCount, RTVs, false, nullptr);
// Set defaults graphics states
GraphicsViewPort defaultViewport;
defaultViewport.X = 0.f;
defaultViewport.Y = 0.f;
defaultViewport.Width = static_cast<float>(frameBufferWidth);
defaultViewport.Height = static_cast<float>(frameBufferHeight);
defaultViewport.MinDepth = 0.f;
defaultViewport.MaxDepth = 1.f;
SetViewPort(commandList, defaultViewport);
Rectangle defaultScissor;
defaultScissor.X = 0;
defaultScissor.Y = 0;
defaultScissor.Width = static_cast<int32>(frameBufferWidth);
defaultScissor.Height = static_cast<int32>(frameBufferHeight);
SetScissorRect(commandList, defaultScissor);
SetStencilReference(commandList, 0);
FColor blendConstants;
blendConstants.R = 1.0f;
blendConstants.G = 1.0f;
blendConstants.B = 1.0f;
blendConstants.A = 1.0f;
SetBlendConstants(commandList, blendConstants);
}
void EndRenderPass(NonNullPtr<CommandList> commandList)
{
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
// Reset Color Target state and optionally resolve color texture
for (uint32 idx = 0; idx < GPUDriver::kMaxColorTargetInfo; ++idx)
{
if (d3d12CommandList->ColorTargetSubresources[idx])
{
if (d3d12CommandList->ColorResolveSubresources[idx])
{
Internal::TextureSubresourceBarrier(d3d12CommandList, D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_RESOLVE_SOURCE,
d3d12CommandList->ColorTargetSubresources[idx]);
ID3D12GraphicsCommandList_ResolveSubresource(
d3d12CommandList->GraphicsCommandList.CommandList,
d3d12CommandList->ColorResolveSubresources[idx]->Parent->Resource,
d3d12CommandList->ColorResolveSubresources[idx]->Index,
d3d12CommandList->ColorTargetSubresources[idx]->Parent->Resource,
d3d12CommandList->ColorTargetSubresources[idx]->Index,
Internal::ConvertToD3D12TextureFormat(
d3d12CommandList->ColorTargetSubresources[idx]->Parent->Container->Header.CreateInfo.Format));
Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList,
d3d12CommandList->ColorTargetSubresources[idx],
D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList,
d3d12CommandList->ColorResolveSubresources[idx],
D3D12_RESOURCE_STATE_RESOLVE_DEST);
}
else
{
Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList,
d3d12CommandList->ColorTargetSubresources[idx],
D3D12_RESOURCE_STATE_RENDER_TARGET);
}
}
}
// TODO : Write Depth stencil
// TODO : Reset graphics pipeline
ID3D12GraphicsCommandList_OMSetRenderTargets(d3d12CommandList->GraphicsCommandList.CommandList, 0, NULL, false, NULL);
// Reset bind states
ZeroArray(d3d12CommandList->ColorTargetSubresources);
ZeroArray(d3d12CommandList->ColorResolveSubresources);
// TODO : reset depth stencil subresources
// TODO : vertex buffer
// TODO :Vertex sampler and fragment sampler
}
} // namespace Juliet::D3D12

View File

@@ -0,0 +1,12 @@
#pragma once
#include <core/Common/NonNullPtr.h>
#include <Graphics/D3D12/DX12CommandList.h>
#include <Graphics/RenderPass.h>
namespace Juliet::D3D12
{
extern void BeginRenderPass(NonNullPtr<CommandList> commandList, NonNullPtr<const ColorTargetInfo> colorTargetInfos,
uint32 colorTargetInfoCount);
extern void EndRenderPass(NonNullPtr<CommandList> commandList);
} // namespace Juliet::D3D12

View File

@@ -0,0 +1,178 @@
#include <pch.h>
#include <Core/Memory/Allocator.h>
#include <Graphics/D3D12/D3D12Synchronization.h>
#include <Graphics/D3D12/DX12CommandList.h>
#include <Graphics/D3D12/DX12GraphicsDevice.h>
#include <Graphics/D3D12/DX12Utils.h>
namespace Juliet::D3D12
{
namespace
{
void ReleaseFenceToPool(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12Fence> fence)
{
if (driver->AvailableFenceCount + 1 >= driver->AvailableFenceCapacity)
{
driver->AvailableFenceCapacity = driver->AvailableFenceCapacity * 2;
driver->AvailableFences = static_cast<D3D12Fence**>(
Realloc(driver->AvailableFences, sizeof(D3D12Fence*) * driver->AvailableFenceCapacity));
}
driver->AvailableFences[driver->AvailableFenceCount] = fence;
driver->AvailableFenceCount += 1;
}
} // namespace
bool Wait(NonNullPtr<GPUDriver> driver)
{
auto d3d12driver = static_cast<D3D12Driver*>(driver.Get());
D3D12Fence* fence = Internal::AcquireFence(d3d12driver);
if (!fence)
{
return false;
}
if (d3d12driver->GraphicsQueue)
{
// Insert a signal into the end of the command queue...
ID3D12CommandQueue_Signal(d3d12driver->GraphicsQueue, fence->Handle, D3D12_FENCE_SIGNAL_VALUE);
// ...and then block on it.
if (ID3D12Fence_GetCompletedValue(fence->Handle) != D3D12_FENCE_SIGNAL_VALUE)
{
HRESULT result = ID3D12Fence_SetEventOnCompletion(fence->Handle, D3D12_FENCE_SIGNAL_VALUE, fence->Event);
if (FAILED(result))
{
LogError(d3d12driver, "Setting fence event failed!", result);
return false;
}
DWORD waitResult = WaitForSingleObject(fence->Event, INFINITE);
if (waitResult == WAIT_FAILED)
{
LogError(d3d12driver, "Wait failed!", result);
return false;
}
}
}
ReleaseFence(driver, reinterpret_cast<Fence*>(fence));
bool result = true;
// Clean up
for (int32 idx = d3d12driver->SubmittedCommandListCount - 1; idx >= 0; idx -= 1)
{
result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false);
}
return result;
}
bool QueryFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence)
{
return true;
}
void ReleaseFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence)
{
auto d3d12driver = static_cast<D3D12Driver*>(driver.Get());
auto d3d12Fence = reinterpret_cast<D3D12Fence*>(fence.Get());
if (--d3d12Fence->ReferenceCount == 0)
{
ReleaseFenceToPool(d3d12driver, d3d12Fence);
}
}
namespace Internal
{
void ResourceBarrier(NonNullPtr<D3D12CommandList> 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<D3D12_RESOURCE_BARRIER_FLAGS>(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<D3D12_RESOURCE_BARRIER_FLAGS>(0);
barrierDesc[numBarriers].UAV.pResource = resource;
numBarriers += 1;
}
if (numBarriers > 0)
{
ID3D12GraphicsCommandList_ResourceBarrier(commandList->GraphicsCommandList.CommandList, numBarriers, barrierDesc);
}
}
D3D12Fence* AcquireFence(NonNullPtr<D3D12Driver> driver)
{
D3D12Fence* fence;
ID3D12Fence* handle;
// TODO :Thread safe (lock + atomic)
if (driver->AvailableFenceCount == 0)
{
HRESULT result = ID3D12Device_CreateFence(driver->D3D12Device, D3D12_FENCE_UNSIGNALED_VALUE, D3D12_FENCE_FLAG_NONE,
IID_ID3D12Fence, reinterpret_cast<void**>(&handle));
if (FAILED(result))
{
LogError(driver, "Failed to create fence!", result);
return nullptr;
}
fence = static_cast<D3D12Fence*>(Calloc(1, sizeof(D3D12Fence)));
if (!fence)
{
ID3D12Fence_Release(handle);
return nullptr;
}
fence->Handle = handle;
fence->Event = CreateEvent(nullptr, false, false, nullptr);
fence->ReferenceCount = 0;
}
else
{
fence = driver->AvailableFences[driver->AvailableFenceCount - 1];
driver->AvailableFenceCount -= 1;
ID3D12Fence_Signal(fence->Handle, D3D12_FENCE_UNSIGNALED_VALUE);
}
fence->ReferenceCount += 1;
return fence;
}
void DestroyFence(NonNullPtr<D3D12Fence> fence)
{
if (fence->Handle)
{
ID3D12Fence_Release(fence->Handle);
}
if (fence->Event)
{
CloseHandle(fence->Event);
}
Free(fence.Get());
}
} // namespace Internal
} // namespace Juliet::D3D12

View File

@@ -0,0 +1,41 @@
#pragma once
#include <Core/Common/NonNullPtr.h>
#include <Graphics/D3D12/D3D12Common.h>
#include <Graphics/GraphicsDevice.h>
namespace Juliet
{
struct Fence;
struct GPUDriver;
} // namespace Juliet
namespace Juliet::D3D12
{
#define D3D12_FENCE_UNSIGNALED_VALUE 0
#define D3D12_FENCE_SIGNAL_VALUE 1
// Forward Declare
struct D3D12CommandList;
struct D3D12Fence
{
ID3D12Fence* Handle;
HANDLE Event; // used for blocking
int32 ReferenceCount; // TODO : Atomic
};
extern bool Wait(NonNullPtr<GPUDriver> driver);
extern bool QueryFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
extern void ReleaseFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
namespace Internal
{
extern void ResourceBarrier(NonNullPtr<D3D12CommandList> commandList, D3D12_RESOURCE_STATES sourceState,
D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource,
uint32 subresourceIndex, bool needsUavBarrier);
extern D3D12Fence* AcquireFence(NonNullPtr<D3D12Driver> driver);
extern void DestroyFence(NonNullPtr<D3D12Fence> fence);
} // namespace Internal
} // namespace Juliet::D3D12

View File

@@ -1,8 +1,240 @@
#include <pch.h>
#include <Core/Common/EnumUtils.h>
#include <Graphics/D3D12/D3D12Synchronization.h>
#include <Graphics/D3D12/D3D12Texture.h>
#include <Graphics/D3D12/DX12CommandList.h>
namespace Juliet::D3D12
{
namespace
{
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_UNORM, // D16_UNORM
DXGI_FORMAT_R24_UNORM_X8_TYPELESS, // D24_UNORM
DXGI_FORMAT_R32_FLOAT, // D32_FLOAT
DXGI_FORMAT_R24_UNORM_X8_TYPELESS, // D24_UNORM_S8_UINT
DXGI_FORMAT_R32_FLOAT_X8X24_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
};
}
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;
}
} // namespace
namespace Internal
{
D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr<D3D12CommandList> commandList,
NonNullPtr<D3D12TextureContainer> container,
uint32 layer, uint32 level, bool shouldCycle,
D3D12_RESOURCE_STATES newTextureUsage)
{
D3D12TextureSubresource* subresource = Internal::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 = Internal::FetchTextureSubresource(container, layer, level);
}
Internal::TextureSubresourceTransitionFromDefaultUsage(commandList, subresource, newTextureUsage);
return subresource;
}
D3D12TextureSubresource* FetchTextureSubresource(NonNullPtr<D3D12TextureContainer> container, uint32 layer, uint32 level)
{
uint32 index = ComputeSubresourceIndex(level, layer, container->Header.CreateInfo.MipLevelCount);
return &container->ActiveTexture->Subresources[index];
}
void TextureSubresourceBarrier(NonNullPtr<D3D12CommandList> commandList, D3D12_RESOURCE_STATES sourceState,
D3D12_RESOURCE_STATES destinationState, NonNullPtr<D3D12TextureSubresource> textureSubresource)
{
TextureUsageFlag currentFlag = textureSubresource->Parent->Container->Header.CreateInfo.Flags;
bool needsUAVBarrier =
((currentFlag & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None) ||
((currentFlag & TextureUsageFlag::ComputeStorageSimultaneousReadWrite) != TextureUsageFlag::None);
Internal::ResourceBarrier(commandList, sourceState, destinationState, textureSubresource->Parent->Resource,
textureSubresource->Index, needsUAVBarrier);
}
void TextureSubresourceTransitionFromDefaultUsage(NonNullPtr<D3D12CommandList> commandList,
NonNullPtr<D3D12TextureSubresource> subresource,
D3D12_RESOURCE_STATES toTextureUsage)
{
D3D12_RESOURCE_STATES defaultUsage =
GetDefaultTextureResourceState(subresource->Parent->Container->Header.CreateInfo.Flags);
TextureSubresourceBarrier(commandList, defaultUsage, toTextureUsage, subresource);
}
void TextureTransitionFromDefaultUsage(NonNullPtr<D3D12CommandList> commandList,
NonNullPtr<D3D12Texture> texture, D3D12_RESOURCE_STATES toTextureUsage)
{
for (uint32 i = 0; i < texture->SubresourceCount; ++i)
{
TextureSubresourceTransitionFromDefaultUsage(commandList, &texture->Subresources[i], toTextureUsage);
}
}
void TextureSubresourceTransitionToDefaultUsage(NonNullPtr<D3D12CommandList> commandList,
NonNullPtr<D3D12TextureSubresource> subresource,
D3D12_RESOURCE_STATES fromTextureUsage)
{
D3D12_RESOURCE_STATES defaultUsage =
GetDefaultTextureResourceState(subresource->Parent->Container->Header.CreateInfo.Flags);
TextureSubresourceBarrier(commandList, fromTextureUsage, defaultUsage, subresource);
}
void TextureTransitionToDefaultUsage(NonNullPtr<D3D12CommandList> commandList, NonNullPtr<D3D12Texture> texture,
D3D12_RESOURCE_STATES fromTextureUsage)
{
for (uint32 i = 0; i < texture->SubresourceCount; ++i)
{
TextureSubresourceTransitionToDefaultUsage(commandList, &texture->Subresources[i], fromTextureUsage);
}
}
// Utils
DXGI_FORMAT ConvertToD3D12TextureFormat(TextureFormat format)
{
return JulietToD3D12_TextureFormat[ToUnderlying(format)];
}
} // namespace Internal
} // namespace Juliet::D3D12

View File

@@ -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,32 @@ namespace Juliet::D3D12
// TODO: Should be atomic to support multithreading
int32 RefCount;
};
namespace Internal
{
extern D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr<D3D12CommandList>,
NonNullPtr<D3D12TextureContainer> container,
uint32 layer, uint32 level, bool shouldCycle,
D3D12_RESOURCE_STATES newTextureUsage);
extern D3D12TextureSubresource* FetchTextureSubresource(NonNullPtr<D3D12TextureContainer> container,
uint32 layer, uint32 level);
extern void TextureSubresourceBarrier(NonNullPtr<D3D12CommandList> commandList,
D3D12_RESOURCE_STATES sourceState, D3D12_RESOURCE_STATES destinationState,
NonNullPtr<D3D12TextureSubresource> textureSubresource);
// Texture usage transition
extern void TextureSubresourceTransitionFromDefaultUsage(NonNullPtr<D3D12CommandList> commandList,
NonNullPtr<D3D12TextureSubresource> subresource,
D3D12_RESOURCE_STATES toTextureUsage);
extern void TextureTransitionFromDefaultUsage(NonNullPtr<D3D12CommandList> commandList,
NonNullPtr<D3D12Texture> texture, D3D12_RESOURCE_STATES toTextureUsage);
extern void TextureSubresourceTransitionToDefaultUsage(NonNullPtr<D3D12CommandList> commandList,
NonNullPtr<D3D12TextureSubresource> subresource,
D3D12_RESOURCE_STATES fromTextureUsage);
extern void TextureTransitionToDefaultUsage(NonNullPtr<D3D12CommandList> commandList, NonNullPtr<D3D12Texture> texture,
D3D12_RESOURCE_STATES fromTextureUsage);
// Utils
extern DXGI_FORMAT ConvertToD3D12TextureFormat(TextureFormat format);
} // namespace Internal
} // namespace Juliet::D3D12

View File

@@ -1,69 +1,108 @@
#include <pch.h>
#include <Core/Memory/Allocator.h>
#include <Graphics/D3D12/D3D12Synchronization.h>
#include <Graphics/D3D12/DX12CommandList.h>
#include <Graphics/D3D12/DX12GraphicsDevice.h>
#include <Graphics/D3D12/DX12Utils.h>
namespace Juliet::D3D12
{
namespace
{
bool HasD3D12CommandList(NonNullPtr<D3D12CommandList> commandList, QueueType queueType)
bool HasD3D12CommandListForQueueType(NonNullPtr<D3D12CommandList> 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<D3D12Driver> driver, NonNullPtr<D3D12CommandList> commandList, QueueType queueType)
bool CreateAllocator(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12CommandListBaseData> 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<void**>(&buffer[ToUnderlying(queueType)]));
if (FAILED(res))
HRESULT result = ID3D12Device5_CreateCommandAllocator(driver->D3D12Device, queueDesc.Type, IID_ID3D12CommandAllocator,
reinterpret_cast<void**>(&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<void**>(&d3d12GraphicsCommandList));
if (FAILED(res))
{
Assert(false && "Error not implemented: cannot create ID3D12GraphicsCommandList6 (graphics or "
"compute command list");
return false;
}
commandListSlot = reinterpret_cast<ID3D12CommandList*>(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<void**>(&d3d12CopyCommandList));
if (FAILED(res))
{
Assert(false &&
"Error not implemented: cannot create ID3D12GraphicsCommandList (copy command list)");
return false;
}
commandListSlot = reinterpret_cast<ID3D12CommandList*>(d3d12CopyCommandList);
}
bool CreateD3D12CommandListForQueueType(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12CommandList> 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<void**>(&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<void**>(&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<void**>(&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<D3D12Driver> driver, QueueType queueType)
@@ -72,6 +111,7 @@ namespace Juliet::D3D12
if (!commandList)
{
Log(LogLevel::Error, LogCategory::Graphics, "Cannot allocate D3D12CommandList: Out of memory");
Internal::DestroyCommandList(commandList);
return false;
}
@@ -80,15 +120,20 @@ namespace Juliet::D3D12
if (!resizedArray)
{
Assert(false &&
"Error not implemented, out of memory, handle that by deallocating stuff and returning false");
Log(LogLevel::Error, LogCategory::Graphics,
"Error not implemented, out of memory, handle that by deallocating stuff and returning false");
Internal::DestroyCommandList(commandList);
return false;
}
driver->AvailableCommandLists = resizedArray;
driver->AvailableCommandLists[driver->AvailableCommandListCapacity] = commandList;
uint32 id = driver->AvailableCommandListCapacity;
driver->AvailableCommandListCapacity += 1;
driver->AvailableCommandLists = resizedArray;
commandList->ID = driver->AvailableCommandListCapacity;
driver->AvailableCommandLists[driver->AvailableCommandListCount] = commandList;
driver->AvailableCommandListCount += 1;
commandList->ID = id;
commandList->Driver = driver;
commandList->PresentDataCapacity = 1;
@@ -96,58 +141,298 @@ namespace Juliet::D3D12
commandList->PresentDatas =
static_cast<D3D12PresentData*>(Calloc(commandList->PresentDataCapacity, sizeof(D3D12PresentData)));
driver->AvailableCommandListCapacity += 1;
// TODO : Simplify this
if (!HasD3D12CommandListForQueueType(commandList, queueType))
{
if (!CreateD3D12CommandListForQueueType(driver, commandList, queueType))
{
Log(LogLevel::Error, LogCategory::Graphics, "Cannot Create D3D12 command list");
Internal::DestroyCommandList(commandList);
return false;
}
}
return true;
}
} // namespace
ID3D12GraphicsCommandList6* GetGraphicsCommandList(NonNullPtr<D3D12CommandList> commandList)
{
return reinterpret_cast<ID3D12GraphicsCommandList6*>(commandList->CommandLists[ToUnderlying(QueueType::Graphics)]);
}
D3D12CommandList* AcquireCommandListFromPool(NonNullPtr<D3D12Driver> 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;
}
} // namespace
CommandList* AcquireCommandList(NonNullPtr<GPUDriver> driver, QueueType queueType)
{
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
uint8 currentCommandListIndex = d3d12Driver->CommandListCount;
if (currentCommandListIndex >= d3d12Driver->AvailableCommandListCapacity)
D3D12CommandList* commandList = AcquireCommandListFromPool(d3d12Driver, queueType);
// Get Proper allocator for the frame and reset both it and the requested queue
uint8 bufferIndex = d3d12Driver->FrameCounter % GPUDriver::kResourceBufferCount;
switch (queueType)
{
if (!AllocateCommandList(d3d12Driver, queueType))
case QueueType::Graphics:
{
return nullptr;
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;
}
D3D12CommandList* commandList = d3d12Driver->AvailableCommandLists[currentCommandListIndex];
if (!HasD3D12CommandList(commandList, queueType))
{
if (!CreateD3D12CommandList(d3d12Driver, commandList, queueType))
{
// TODO Shoud destroy the command list here
return nullptr;
}
}
commandList->AutoReleaseFence = true;
return reinterpret_cast<CommandList*>(commandList);
}
bool SubmitCommandLists(NonNullPtr<GPUDriver> driver)
bool SubmitCommandLists(NonNullPtr<CommandList> commandList)
{
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
bool success = true;
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
auto* d3d12Driver = d3d12CommandList->Driver;
// TODO : Use QueueType to choose the correct CommandList and Command Queue
// Only use graphics for now
uint8 commandLastIndex = d3d12Driver->CommandListCount;
// Transition present textures to present mode
for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1)
{
uint32 swapchainIndex = d3d12CommandList->PresentDatas[i].SwapChainImageIndex;
D3D12TextureContainer* container =
&d3d12CommandList->PresentDatas[i].WindowData->SwapChainTextureContainers[swapchainIndex];
D3D12TextureSubresource* subresource = Internal::FetchTextureSubresource(container, 0, 0);
// 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);
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;
ID3D12GraphicsCommandList_ResourceBarrier(d3d12CommandList->GraphicsCommandList.CommandList, 1, &barrierDesc);
}
// Notify the command buffer that we have completed recording
HRESULT result = ID3D12GraphicsCommandList_Close(d3d12CommandList->GraphicsCommandList.CommandList);
if (FAILED(result))
{
success = false;
LogError(d3d12Driver, "Failed to close command list!", result);
return false;
}
ID3D12CommandList* commandLists[1];
result = ID3D12GraphicsCommandList_QueryInterface(d3d12CommandList->GraphicsCommandList.CommandList,
IID_ID3D12CommandList, reinterpret_cast<void**>(&commandLists[0]));
if (FAILED(result))
{
LogError(d3d12Driver, "Failed to convert command list!", result);
return false;
}
// Submit the command list to the queue
ID3D12CommandQueue_ExecuteCommandLists(d3d12Driver->GraphicsQueue, 1, commandLists);
ID3D12CommandList_Release(commandLists[0]);
// Acquire a fence and set it to the in-flight fence
d3d12CommandList->InFlightFence = Internal::AcquireFence(d3d12Driver);
if (!d3d12CommandList->InFlightFence)
{
return false;
}
// Mark that a fence should be signaled after command list execution
result = ID3D12CommandQueue_Signal(d3d12Driver->GraphicsQueue, d3d12CommandList->InFlightFence->Handle, D3D12_FENCE_SIGNAL_VALUE);
if (FAILED(result))
{
LogError(d3d12Driver, "Failed to enqueue fence signal!", result);
return false;
}
// Mark the command list as submitted
if (d3d12Driver->SubmittedCommandListCount + 1 >= d3d12Driver->SubmittedCommandListCapacity)
{
d3d12Driver->SubmittedCommandListCapacity = d3d12Driver->SubmittedCommandListCount + 1;
d3d12Driver->SubmittedCommandLists = static_cast<D3D12CommandList**>(
Realloc(d3d12Driver->SubmittedCommandLists, sizeof(D3D12CommandList*) * 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 = IDXGISwapChain_Present(windowData->SwapChain, syncInterval, presentFlags);
if (FAILED(result))
{
result = false;
}
ID3D12Resource_Release(
windowData->SwapChainTextureContainers[presentData->SwapChainImageIndex].ActiveTexture->Resource);
windowData->InFlightFences[windowData->WindowFrameCounter] = reinterpret_cast<Fence*>(d3d12CommandList->InFlightFence);
d3d12CommandList->InFlightFence->ReferenceCount += 1;
windowData->WindowFrameCounter = (windowData->WindowFrameCounter + 1) % d3d12Driver->FramesInFlight;
}
// TODO : Correctly clean up and destroy
// Check for cleanups
for (int32 i = d3d12Driver->SubmittedCommandListCount - 1; i >= 0; i -= 1)
{
uint64 fenceValue = ID3D12Fence_GetCompletedValue(d3d12Driver->SubmittedCommandLists[i]->InFlightFence->Handle);
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE)
{
result &= Internal::CleanCommandList(d3d12Driver, d3d12Driver->SubmittedCommandLists[i], false);
}
}
// TODO Destroy anything (buffer, texture, etc...)
++d3d12Driver->FrameCounter;
return success;
}
void SetViewPort(NonNullPtr<CommandList> commandList, const GraphicsViewPort& viewPort)
{
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(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;
ID3D12GraphicsCommandList_RSSetViewports(d3d12CommandList->GraphicsCommandList.CommandList, 1, &d3d12Viewport);
}
void SetScissorRect(NonNullPtr<CommandList> commandList, const Rectangle& rectangle)
{
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(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;
ID3D12GraphicsCommandList_RSSetScissorRects(d3d12CommandList->GraphicsCommandList.CommandList, 1, &scissorRect);
}
void SetBlendConstants(NonNullPtr<CommandList> commandList, FColor blendConstants)
{
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
FLOAT blendFactor[4] = { blendConstants.R, blendConstants.G, blendConstants.B, blendConstants.A };
ID3D12GraphicsCommandList_OMSetBlendFactor(d3d12CommandList->GraphicsCommandList.CommandList, blendFactor);
}
void SetStencilReference(NonNullPtr<CommandList> commandList, uint8 reference)
{
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
ID3D12GraphicsCommandList_OMSetStencilRef(d3d12CommandList->GraphicsCommandList.CommandList, reference);
}
namespace Internal
{
void DestroyCommandList(NonNullPtr<D3D12CommandList> commandList)
{
// TODO : Handle other kind of command list (copy compute)
if (commandList->GraphicsCommandList.CommandList)
{
ID3D12GraphicsCommandList_Release(commandList->GraphicsCommandList.CommandList);
}
for (auto* allocator : commandList->GraphicsCommandList.Allocator)
{
if (allocator)
{
ID3D12CommandAllocator_Release(allocator);
}
}
Free(commandList->PresentDatas);
Free(commandList.Get());
}
bool CleanCommandList(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12CommandList> commandList, bool cancel)
{
// No more presentation data
commandList->PresentDataCount = 0;
// Release Fence if needed
if (commandList->AutoReleaseFence)
{
ReleaseFence(driver.Get(), reinterpret_cast<Fence*>(commandList->InFlightFence));
commandList->InFlightFence = nullptr;
}
// Return the command list to the pool
if (driver->AvailableCommandListCount == driver->AvailableCommandListCapacity)
{
driver->AvailableCommandListCapacity += 1;
driver->AvailableCommandLists = static_cast<D3D12CommandList**>(
Realloc(driver->AvailableCommandLists, driver->AvailableCommandListCapacity * sizeof(D3D12CommandList*)));
}
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;
}
}
}
return true;
}
} // namespace Internal
} // namespace Juliet::D3D12

View File

@@ -1,19 +1,37 @@
#pragma once
#include <Core/Common/EnumUtils.h>
#include <Core/Common/NonNullPtr.h>
#include <Core/Math/Shape.h>
#include <Graphics/D3D12/DX12Includes.h>
#include <Graphics/GraphicsDevice.h>
namespace Juliet::D3D12
{
// Forward Declare
struct D3D12Driver;
struct D3D12Fence;
struct D3D12TextureSubresource;
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 +42,30 @@ 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)];
D3D12Fence* InFlightFence;
bool AutoReleaseFence;
D3D12GraphicsCommandListData GraphicsCommandList;
D3D12GraphicsCommandListData ComputeCommandList;
D3D12CopyCommandListData CopyCommandList;
D3D12TextureSubresource* ColorTargetSubresources[GPUDriver::kMaxColorTargetInfo];
D3D12TextureSubresource* ColorResolveSubresources[GPUDriver::kMaxColorTargetInfo];
};
ID3D12GraphicsCommandList6* GetGraphicsCommandList(NonNullPtr<D3D12CommandList> commandList);
extern CommandList* AcquireCommandList(NonNullPtr<GPUDriver> driver, QueueType queueType);
extern bool SubmitCommandLists(NonNullPtr<GPUDriver> driver);
extern bool SubmitCommandLists(NonNullPtr<CommandList> commandList);
extern void SetViewPort(NonNullPtr<CommandList> commandList, const GraphicsViewPort& viewPort);
extern void SetScissorRect(NonNullPtr<CommandList> commandList, const Rectangle& rectangle);
extern void SetBlendConstants(NonNullPtr<CommandList> commandList, FColor blendConstants);
extern void SetStencilReference(NonNullPtr<CommandList> commandList, uint8 reference);
namespace Internal
{
extern void DestroyCommandList(NonNullPtr<D3D12CommandList> commandList);
extern bool CleanCommandList(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12CommandList> commandList, bool cancel);
} // namespace Internal
} // namespace Juliet::D3D12

View File

@@ -3,6 +3,8 @@
#include <core/Common/NonNullPtr.h>
#include <Core/DynLib/DynamicLibrary.h>
#include <Core/Memory/Allocator.h>
#include <Graphics/D3D12/D3D12RenderPass.h>
#include <Graphics/D3D12/D3D12Synchronization.h>
#include <Graphics/D3D12/DX12CommandList.h>
#include <Graphics/D3D12/DX12GraphicsDevice.h>
#include <Graphics/D3D12/DX12Includes.h>
@@ -167,15 +169,42 @@ namespace Juliet::D3D12
void DestroyDriver_Internal(NonNullPtr<D3D12Driver> driver)
{
// Destroy pools
for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1)
{
if (driver->StagingDescriptorPools[i])
{
DestroyStagingDescriptorPool(driver->StagingDescriptorPools[i]);
Internal::DestroyStagingDescriptorPool(driver->StagingDescriptorPools[i]);
driver->StagingDescriptorPools[i] = nullptr;
}
}
// Release command buffers
for (uint32 i = 0; i < driver->AvailableCommandListCount; i += 1)
{
if (driver->AvailableCommandLists[i])
{
Internal::DestroyCommandList(driver->AvailableCommandLists[i]);
driver->AvailableCommandLists[i] = nullptr;
}
}
// Release fences
for (uint32 i = 0; i < driver->AvailableFenceCount; i += 1)
{
if (driver->AvailableFences[i])
{
Internal::DestroyFence(driver->AvailableFences[i]);
driver->AvailableFences[i] = nullptr;
}
}
// Clean allocations
Free(driver->AvailableCommandLists);
Free(driver->SubmittedCommandLists);
//Free(driver->WindowData); // TODO Should free the vector of WindowData, but we have only one for now
Free(driver->AvailableFences);
if (driver->IndirectDrawCommandSignature)
{
ID3D12CommandSignature_Release(driver->IndirectDrawCommandSignature);
@@ -249,7 +278,7 @@ namespace Juliet::D3D12
windowData->Window = window;
if (!CreateSwapChain(d3d12Driver, windowData, SwapChainComposition::SDR, PresentMode::VSync))
if (!Internal::CreateSwapChain(d3d12Driver, windowData, SwapChainComposition::SDR, PresentMode::VSync))
{
Log(LogLevel::Error, LogCategory::Graphics, "AttachToWindow failure: Cannot create Swap Chain.");
Free(windowData);
@@ -265,12 +294,21 @@ namespace Juliet::D3D12
void DetachFromWindow(NonNullPtr<GPUDriver> driver, NonNullPtr<Window> window)
{
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
auto* windowData = d3d12Driver->WindowData;
Assert(windowData && "Trying to destroy a swapchain but no Window Data exists");
Assert(d3d12Driver->WindowData && "Trying to destroy a swapchain but no Window Data exists");
Wait(driver);
// TODO : Wait for any remaining work and release the fences.
for (uint32 idx = 0; idx < GPUDriver::kMaxFramesInFlight; idx += 1)
{
if (windowData->InFlightFences[idx] != nullptr)
{
ReleaseFence(driver, windowData->InFlightFences[idx]);
windowData->InFlightFences[idx] = nullptr;
}
}
DestroySwapChain(d3d12Driver, d3d12Driver->WindowData);
Internal::DestroySwapChain(d3d12Driver, d3d12Driver->WindowData);
Free(d3d12Driver->WindowData);
d3d12Driver->WindowData = nullptr;
@@ -517,27 +555,46 @@ namespace Juliet::D3D12
return nullptr;
}
auto device = static_cast<GraphicsDevice*>(Calloc(1, sizeof(GraphicsDevice)));
if (!device)
// Create Pools
driver->SubmittedCommandListCapacity = 4;
driver->SubmittedCommandListCount = 0;
driver->SubmittedCommandLists =
static_cast<D3D12CommandList**>(Calloc(driver->SubmittedCommandListCapacity, sizeof(D3D12CommandList*)));
if (!driver->SubmittedCommandLists)
{
DestroyDriver_Internal(driver);
return nullptr;
}
// Create Pools
driver->AvailableFenceCapacity = 4;
driver->AvailableFenceCount = 0;
driver->AvailableFences = static_cast<D3D12Fence**>(Calloc(driver->AvailableFenceCapacity, sizeof(D3D12Fence*)));
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<D3D12_DESCRIPTOR_HEAP_TYPE>(i));
Internal::CreateStagingDescriptorPool(driver, static_cast<D3D12_DESCRIPTOR_HEAP_TYPE>(i));
if (driver->StagingDescriptorPools[i] == nullptr)
{
DestroyDriver_Internal(driver);
return NULL;
return nullptr;
}
}
auto device = static_cast<GraphicsDevice*>(Calloc(1, sizeof(GraphicsDevice)));
if (!device)
{
DestroyDriver_Internal(driver);
return nullptr;
}
// Assign Functions to the device
device->DestroyDevice = DestroyGraphicsDevice;
@@ -549,6 +606,18 @@ namespace Juliet::D3D12
device->AcquireCommandList = AcquireCommandList;
device->SubmitCommandLists = SubmitCommandLists;
device->BeginRenderPass = BeginRenderPass;
device->EndRenderPass = EndRenderPass;
device->SetViewPort = SetViewPort;
device->SetScissorRect = SetScissorRect;
device->SetBlendConstants = SetBlendConstants;
device->SetStencilReference = SetStencilReference;
device->Wait = Wait;
device->QueryFence = QueryFence;
device->ReleaseFence = ReleaseFence;
device->Driver = driver;
driver->GraphicsDevice = device;

View File

@@ -12,7 +12,9 @@ namespace Juliet
namespace Juliet::D3D12
{
// Forward Declare
struct D3D12CommandList;
struct D3D12Fence;
struct D3D12WindowData
{
@@ -26,7 +28,9 @@ namespace Juliet::D3D12
PresentMode PresentMode;
uint32 FrameCounter;
Fence* InFlightFences[GPUDriver::kMaxFramesInFlight];
uint32 WindowFrameCounter; // Specific to that window. See GraphicsDevice for global counter
uint32 Width;
uint32 Height;
};
@@ -63,10 +67,20 @@ namespace Juliet::D3D12
// Resources
D3D12CommandList** AvailableCommandLists;
uint8 AvailableCommandListCapacity;
uint8 AvailableCommandListCount;
D3D12CommandList** SubmittedCommandLists;
uint8 SubmittedCommandListCapacity;
uint8 SubmittedCommandListCount;
D3D12Fence** AvailableFences;
uint32 AvailableFenceCount;
uint32 AvailableFenceCapacity;
D3D12StagingDescriptorPool* StagingDescriptorPools[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES];
uint8 FramesInFlight;
uint8 FramesInFlight;
uint64 FrameCounter = 0; // Number of frame since inception
bool IsTearingSupported : 1;
bool IsUMAAvailable : 1;

View File

@@ -26,3 +26,6 @@
#ifdef __IDXGIInfoQueue_INTERFACE_DEFINED__
#define IDXGIINFOQUEUE_SUPPORTED
#endif
#undef min
#undef max

View File

@@ -3,13 +3,14 @@
#include <Core/HAL/Display/Win32/Win32Window.h>
#include <Core/Memory/Allocator.h>
#include <Graphics/D3D12/D3D12Texture.h>
#include <Graphics/D3D12/DX12CommandList.h>
#include <Graphics/D3D12/DX12GraphicsDevice.h>
#include <Graphics/D3D12/DX12Includes.h>
#include <Graphics/D3D12/DX12SwapChain.h>
#include <Graphics/D3D12/DX12Utils.h>
#include <algorithm>
#include <DX12CommandList.h>
namespace Juliet::D3D12
{
namespace
@@ -105,7 +106,7 @@ namespace Juliet::D3D12
texture->IndexInContainer = 0;
// Assign SRV to the swapchain texture
AssignStagingDescriptor(driver, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, texture->SRVHandle);
Internal::AssignStagingDescriptor(driver, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, texture->SRVHandle);
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.Format = SwapchainCompositionToTextureFormat[ToUnderlying(composition)];
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
@@ -118,7 +119,7 @@ namespace Juliet::D3D12
// Assign RTV to the swapchain texture
DXGI_FORMAT swapchainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)];
AssignStagingDescriptor(driver, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, texture->Subresources[0].RTVHandles[0]);
Internal::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;
@@ -162,11 +163,10 @@ namespace Juliet::D3D12
if (d3d12CommandList->PresentDataCount == d3d12CommandList->PresentDataCapacity)
{
d3d12CommandList->PresentDataCapacity += 1;
d3d12CommandList->PresentDatas =
static_cast<D3D12PresentData*>(Realloc(d3d12CommandList->PresentDatas,
d3d12CommandList->PresentDataCapacity * sizeof(D3D12PresentData)));
d3d12CommandList->PresentDatas = static_cast<D3D12PresentData*>(
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 +179,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<Texture*>(&windowData->SwapChainTextureContainers[swapchainIndex]);
@@ -187,136 +187,140 @@ namespace Juliet::D3D12
}
} // namespace
bool CreateSwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData,
SwapChainComposition composition, PresentMode presentMode)
{
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;
}
// TODO: I have no way to test HDR easily except the steamdeck
DXGI_FORMAT swapChainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)];
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;
}
if (composition != SwapChainComposition::SDR)
{
IDXGISwapChain3_SetColorSpace1(swapChain3, SwapchainCompositionToColorSpace[ToUnderlying(composition)]);
}
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->SwapChainColorSpace = SwapchainCompositionToColorSpace[ToUnderlying(composition)];
windowData->SwapChainComposition = composition;
windowData->FrameCounter = 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))
{
IDXGISwapChain3_Release(swapChain3);
return false;
}
}
return true;
}
bool AcquireSwapChainTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapChainTexture)
{
return AcquireSwapChainTexture(false, commandList, window, swapChainTexture);
}
void DestroySwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData)
namespace Internal
{
for (uint32 idx = 0; idx < windowData->SwapChainTextureCount; ++idx)
bool CreateSwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData,
SwapChainComposition composition, PresentMode presentMode)
{
ReleaseStagingDescriptor(driver, windowData->SwapChainTextureContainers[idx].ActiveTexture->SRVHandle);
ReleaseStagingDescriptor(driver, windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles[0]);
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;
}
Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles);
Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources);
Free(windowData->SwapChainTextureContainers[idx].ActiveTexture);
Free(windowData->SwapChainTextureContainers[idx].Textures);
// TODO: I have no way to test HDR easily except the steamdeck
DXGI_FORMAT swapChainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)];
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;
}
if (composition != SwapChainComposition::SDR)
{
IDXGISwapChain3_SetColorSpace1(swapChain3, SwapchainCompositionToColorSpace[ToUnderlying(composition)]);
}
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->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))
{
IDXGISwapChain3_Release(swapChain3);
return false;
}
}
return true;
}
IDXGISwapChain_Release(windowData->SwapChain);
windowData->SwapChain = nullptr;
}
void DestroySwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData)
{
for (uint32 idx = 0; idx < windowData->SwapChainTextureCount; ++idx)
{
ReleaseStagingDescriptor(driver, windowData->SwapChainTextureContainers[idx].ActiveTexture->SRVHandle);
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);
}
IDXGISwapChain_Release(windowData->SwapChain);
windowData->SwapChain = nullptr;
}
} // namespace Internal
} // namespace Juliet::D3D12

View File

@@ -3,11 +3,16 @@
namespace Juliet::D3D12
{
// Forward Declare
struct D3D12Driver;
struct D3D12WindowData;
extern bool CreateSwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData,
SwapChainComposition composition, PresentMode presentMode);
extern bool AcquireSwapChainTexture(NonNullPtr<CommandList> commandList, NonNullPtr<Window> window, Texture** swapChainTexture);
extern void DestroySwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData);
namespace Internal
{
extern bool CreateSwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData,
SwapChainComposition composition, PresentMode presentMode);
extern void DestroySwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData);
} // namespace Internal
} // namespace Juliet::D3D12

View File

@@ -38,7 +38,7 @@ namespace Juliet::D3D12
}
// Ensure valid range
dwChars = std::min<DWORD>(dwChars, MAX_ERROR_LEN);
dwChars = Min<DWORD>(dwChars, MAX_ERROR_LEN);
// Trim whitespace from tail of message
while (dwChars > 0)

View File

@@ -65,9 +65,7 @@ namespace Juliet
bool AttachToWindow(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window)
{
GPUDriver* driver = device->Driver;
bool result = device->AttachToWindow(driver, window);
return result;
return device->AttachToWindow(driver, window);
}
void DetachFromWindow(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window)
@@ -93,26 +91,88 @@ namespace Juliet
{
GPUDriver* driver = device->Driver;
CommandList* cmdList = device->AcquireCommandList(driver, queueType);
if (!cmdList)
{
return nullptr;
}
auto header = reinterpret_cast<CommandListHeader*>(cmdList);
header->Device = device.Get();
driver->CommandListCount += 1;
auto header = reinterpret_cast<CommandListHeader*>(cmdList);
header->Device = device.Get();
header->RenderPass.CommandList = cmdList;
return cmdList;
}
void SubmitCommandLists(NonNullPtr<GraphicsDevice> device)
void SubmitCommandLists(NonNullPtr<CommandList> commandList)
{
GPUDriver* driver = device->Driver;
device->SubmitCommandLists(driver);
auto* commandListHeader = reinterpret_cast<CommandListHeader*>(commandList.Get());
driver->CommandListCount = 0;
commandListHeader->Submitted = true;
commandListHeader->Device->SubmitCommandLists(commandList);
}
RenderPass* BeginRenderPass(NonNullPtr<CommandList> commandList, ColorTargetInfo& colorTargetInfo)
{
return BeginRenderPass(commandList, &colorTargetInfo, 1);
}
RenderPass* BeginRenderPass(NonNullPtr<CommandList> commandList, NonNullPtr<const ColorTargetInfo> colorTargetInfos,
uint32 colorTargetInfoCount)
{
if (colorTargetInfoCount > GPUDriver::kMaxColorTargetInfo)
{
Log(LogLevel::Error, LogCategory::Graphics, "BeginRenderPass: ColorTargetInfoCount is > than kMaxColorTargetInfo");
return nullptr;
}
auto* header = reinterpret_cast<CommandListHeader*>(commandList.Get());
header->Device->BeginRenderPass(commandList, colorTargetInfos, colorTargetInfoCount);
header->RenderPass.IsInProgress = true;
return reinterpret_cast<RenderPass*>(&header->RenderPass);
}
void EndRenderPass(NonNullPtr<RenderPass> renderPass)
{
auto* commandList = reinterpret_cast<GPUPass*>(renderPass.Get())->CommandList;
auto* commandListHeader = reinterpret_cast<CommandListHeader*>(commandList);
commandListHeader->Device->EndRenderPass(commandList);
commandListHeader->RenderPass.IsInProgress = false;
}
void SetGraphicsViewPort(NonNullPtr<RenderPass> renderPass, const GraphicsViewPort& viewPort)
{
auto* commandList = reinterpret_cast<GPUPass*>(renderPass.Get())->CommandList;
auto* commandListHeader = reinterpret_cast<CommandListHeader*>(commandList);
commandListHeader->Device->SetViewPort(commandList, viewPort);
}
void SetScissorRect(NonNullPtr<RenderPass> renderPass, const Rectangle& rectangle)
{
auto* commandList = reinterpret_cast<GPUPass*>(renderPass.Get())->CommandList;
auto* commandListHeader = reinterpret_cast<CommandListHeader*>(commandList);
commandListHeader->Device->SetScissorRect(commandList, rectangle);
}
void SetBlendConstants(NonNullPtr<RenderPass> renderPass, FColor blendConstants)
{
auto* commandList = reinterpret_cast<GPUPass*>(renderPass.Get())->CommandList;
auto* commandListHeader = reinterpret_cast<CommandListHeader*>(commandList);
commandListHeader->Device->SetBlendConstants(commandList, blendConstants);
}
void SetStencilReference(NonNullPtr<RenderPass> renderPass, uint8 reference)
{
auto* commandList = reinterpret_cast<GPUPass*>(renderPass.Get())->CommandList;
auto* commandListHeader = reinterpret_cast<CommandListHeader*>(commandList);
commandListHeader->Device->SetStencilReference(commandList, reference);
}
} // namespace Juliet

View File

@@ -7,25 +7,31 @@
namespace Juliet
{
struct Window;
struct TextureHeader
{
TextureCreateInfo CreateInfo;
};
struct GPUPass
{
CommandList* CommandList;
bool IsInProgress : 1;
};
struct CommandListHeader
{
GraphicsDevice* Device = nullptr;
bool AcquiredSwapChain = false;
bool Submitted = false;
GPUPass RenderPass;
};
struct GPUDriver
{
uint8 CommandListCount;
static constexpr uint8 kResourceBufferCount = 2;
static constexpr uint8 kMaxFramesInFlight = 3;
static constexpr uint8 kMaxColorTargetInfo = 4;
};
struct GraphicsDevice
@@ -41,7 +47,22 @@ namespace Juliet
// CommandLists
CommandList* (*AcquireCommandList)(NonNullPtr<GPUDriver> driver, QueueType queueType);
bool (*SubmitCommandLists)(NonNullPtr<GPUDriver> driver);
bool (*SubmitCommandLists)(NonNullPtr<CommandList> commandList);
// RenderPass
void (*BeginRenderPass)(NonNullPtr<CommandList> commandList, NonNullPtr<const ColorTargetInfo> colorTargetInfos,
uint32 colorTargetInfoCount);
void (*EndRenderPass)(NonNullPtr<CommandList> commandList);
void (*SetViewPort)(NonNullPtr<CommandList> commandList, const GraphicsViewPort& viewPort);
void (*SetScissorRect)(NonNullPtr<CommandList> commandList, const Rectangle& viewPort);
void (*SetBlendConstants)(NonNullPtr<CommandList> commandList, FColor blendConstants);
void (*SetStencilReference)(NonNullPtr<CommandList> commandList, uint8 reference);
// Fences
bool (*Wait)(NonNullPtr<GPUDriver> driver);
bool (*QueryFence)(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
void (*ReleaseFence)(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
const char* Name = "Unknown";
GPUDriver* Driver = nullptr;

View File

@@ -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

View File

@@ -13,6 +13,7 @@
// TODO : Replace with message box from framework + call main and not winmain + subsystem
#include <Core/DynLib/DynamicLibrary.h>
#include <Graphics/Graphics.h>
#include <Graphics/RenderPass.h>
#include <Windows.h>
// TODO : Think how to do the draw pipeline.
@@ -97,8 +98,20 @@ void Win32EditorApplication::Update()
return;
}
if (swapChainTexture)
{
ColorTargetInfo colorTargetInfo = {};
colorTargetInfo.TargetTexture = swapChainTexture;
colorTargetInfo.ClearColor = { .R = .5f, .G = .8f, .B = .0f, .A = 1.f };
colorTargetInfo.LoadOperation = LoadOperation::Clear;
colorTargetInfo.StoreOperation = StoreOperation::Store;
RenderPass* renderPass = BeginRenderPass(cmdList, colorTargetInfo);
EndRenderPass(renderPass);
}
// Submit Commands
SubmitCommandLists(GraphicsDevice);
SubmitCommandLists(cmdList);
}
bool Win32EditorApplication::IsRunning()

View File

@@ -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;
};