Swapchain creation and destruction
This commit is contained in:
@@ -136,6 +136,7 @@
|
||||
<ClInclude Include="include\Engine\Engine.h"/>
|
||||
<ClInclude Include="include\Graphics\Graphics.h"/>
|
||||
<ClInclude Include="include\Graphics\GraphicsConfig.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"/>
|
||||
@@ -150,6 +151,8 @@
|
||||
<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\D3D12Texture.h" />
|
||||
<ClInclude Include="src\Graphics\D3D12\DX12CommandList.h"/>
|
||||
<ClInclude Include="src\Graphics\D3D12\DX12GraphicsDevice.h"/>
|
||||
<ClInclude Include="src\Graphics\D3D12\DX12Includes.h"/>
|
||||
@@ -232,6 +235,8 @@
|
||||
<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\D3D12Texture.cpp" />
|
||||
<ClCompile Include="src\Graphics\D3D12\DX12CommandList.cpp"/>
|
||||
<ClCompile Include="src\Graphics\D3D12\DX12GraphicsDevice.cpp"/>
|
||||
<ClCompile Include="src\Graphics\D3D12\DX12SwapChain.cpp"/>
|
||||
|
||||
@@ -33,4 +33,6 @@ namespace Juliet
|
||||
*Byte++ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define MemCopy memcpy
|
||||
} // namespace Juliet
|
||||
|
||||
@@ -105,4 +105,7 @@ namespace Juliet
|
||||
private:
|
||||
Type* InternalPtr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
NonNullPtr(T) -> NonNullPtr<T>;
|
||||
} // namespace Juliet
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
namespace Juliet
|
||||
{
|
||||
// Uninitialized allocation
|
||||
JULIET_API void* Malloc(size_t nb_elem, size_t elem_size);
|
||||
JULIET_API void* Malloc(size_t elem_size);
|
||||
// Initialized to 0 allocation
|
||||
JULIET_API void* Calloc(size_t nb_elem, size_t elem_size);
|
||||
JULIET_API void* Realloc(void* memory, size_t newSize);
|
||||
|
||||
@@ -45,6 +45,25 @@ namespace Juliet
|
||||
Count
|
||||
};
|
||||
|
||||
enum struct SwapChainComposition : uint8
|
||||
{
|
||||
SDR,
|
||||
SDR_LINEAR,
|
||||
HDR_EXTENDED_LINEAR,
|
||||
HDR10_ST2084
|
||||
};
|
||||
|
||||
// PresentMode from highest to lowest latency
|
||||
// Vsync prevents tearing. Enqueue ready images.
|
||||
// Mailbox prevents tearing. When image is ready, replace any pending image
|
||||
// Immediate replace current image as soon as possible. Can cause tearing
|
||||
enum struct PresentMode : uint8
|
||||
{
|
||||
VSync,
|
||||
Mailbox,
|
||||
Immediate
|
||||
};
|
||||
|
||||
// Opaque types
|
||||
struct CommandList;
|
||||
|
||||
|
||||
180
Juliet/include/Graphics/Texture.h
Normal file
180
Juliet/include/Graphics/Texture.h
Normal file
@@ -0,0 +1,180 @@
|
||||
#pragma once
|
||||
#include <D3D12Common.h>
|
||||
|
||||
namespace Juliet
|
||||
{
|
||||
enum struct TextureFormat : uint8
|
||||
{
|
||||
Invalid,
|
||||
|
||||
/* Unsigned Normalized Float Color Formats */
|
||||
A8_UNORM,
|
||||
R8_UNORM,
|
||||
R8G8_UNORM,
|
||||
R8G8B8A8_UNORM,
|
||||
R16_UNORM,
|
||||
R16G16_UNORM,
|
||||
R16G16B16A16_UNORM,
|
||||
R10G10B10A2_UNORM,
|
||||
B5G6R5_UNORM,
|
||||
B5G5R5A1_UNORM,
|
||||
B4G4R4A4_UNORM,
|
||||
B8G8R8A8_UNORM,
|
||||
/* Compressed Unsigned Normalized Float Color Formats */
|
||||
BC1_RGBA_UNORM,
|
||||
BC2_RGBA_UNORM,
|
||||
BC3_RGBA_UNORM,
|
||||
BC4_R_UNORM,
|
||||
BC5_RG_UNORM,
|
||||
BC7_RGBA_UNORM,
|
||||
/* Compressed Signed Float Color Formats */
|
||||
BC6H_RGB_FLOAT,
|
||||
/* Compressed Unsigned Float Color Formats */
|
||||
BC6H_RGB_UFLOAT,
|
||||
/* Signed Normalized Float Color Formats */
|
||||
R8_SNORM,
|
||||
R8G8_SNORM,
|
||||
R8G8B8A8_SNORM,
|
||||
R16_SNORM,
|
||||
R16G16_SNORM,
|
||||
R16G16B16A16_SNORM,
|
||||
/* Signed Float Color Formats */
|
||||
R16_FLOAT,
|
||||
R16G16_FLOAT,
|
||||
R16G16B16A16_FLOAT,
|
||||
R32_FLOAT,
|
||||
R32G32_FLOAT,
|
||||
R32G32B32A32_FLOAT,
|
||||
/* Unsigned Float Color Formats */
|
||||
R11G11B10_UFLOAT,
|
||||
/* Unsigned Integer Color Formats */
|
||||
R8_UINT,
|
||||
R8G8_UINT,
|
||||
R8G8B8A8_UINT,
|
||||
R16_UINT,
|
||||
R16G16_UINT,
|
||||
R16G16B16A16_UINT,
|
||||
R32_UINT,
|
||||
R32G32_UINT,
|
||||
R32G32B32A32_UINT,
|
||||
/* Signed Integer Color Formats */
|
||||
R8_INT,
|
||||
R8G8_INT,
|
||||
R8G8B8A8_INT,
|
||||
R16_INT,
|
||||
R16G16_INT,
|
||||
R16G16B16A16_INT,
|
||||
R32_INT,
|
||||
R32G32_INT,
|
||||
R32G32B32A32_INT,
|
||||
/* SRGB Unsigned Normalized Color Formats */
|
||||
R8G8B8A8_UNORM_SRGB,
|
||||
B8G8R8A8_UNORM_SRGB,
|
||||
/* Compressed SRGB Unsigned Normalized Color Formats */
|
||||
BC1_RGBA_UNORM_SRGB,
|
||||
BC2_RGBA_UNORM_SRGB,
|
||||
BC3_RGBA_UNORM_SRGB,
|
||||
BC7_RGBA_UNORM_SRGB,
|
||||
/* Depth Formats */
|
||||
D16_UNORM,
|
||||
D24_UNORM,
|
||||
D32_FLOAT,
|
||||
D24_UNORM_S8_UINT,
|
||||
D32_FLOAT_S8_UINT,
|
||||
/* Compressed ASTC Normalized Float Color Formats*/
|
||||
ASTC_4x4_UNORM,
|
||||
ASTC_5x4_UNORM,
|
||||
ASTC_5x5_UNORM,
|
||||
ASTC_6x5_UNORM,
|
||||
ASTC_6x6_UNORM,
|
||||
ASTC_8x5_UNORM,
|
||||
ASTC_8x6_UNORM,
|
||||
ASTC_8x8_UNORM,
|
||||
ASTC_10x5_UNORM,
|
||||
ASTC_10x6_UNORM,
|
||||
ASTC_10x8_UNORM,
|
||||
ASTC_10x10_UNORM,
|
||||
ASTC_12x10_UNORM,
|
||||
ASTC_12x12_UNORM,
|
||||
/* Compressed SRGB ASTC Normalized Float Color Formats*/
|
||||
ASTC_4x4_UNORM_SRGB,
|
||||
ASTC_5x4_UNORM_SRGB,
|
||||
ASTC_5x5_UNORM_SRGB,
|
||||
ASTC_6x5_UNORM_SRGB,
|
||||
ASTC_6x6_UNORM_SRGB,
|
||||
ASTC_8x5_UNORM_SRGB,
|
||||
ASTC_8x6_UNORM_SRGB,
|
||||
ASTC_8x8_UNORM_SRGB,
|
||||
ASTC_10x5_UNORM_SRGB,
|
||||
ASTC_10x6_UNORM_SRGB,
|
||||
ASTC_10x8_UNORM_SRGB,
|
||||
ASTC_10x10_UNORM_SRGB,
|
||||
ASTC_12x10_UNORM_SRGB,
|
||||
ASTC_12x12_UNORM_SRGB,
|
||||
/* Compressed ASTC Signed Float Color Formats*/
|
||||
ASTC_4x4_FLOAT,
|
||||
ASTC_5x4_FLOAT,
|
||||
ASTC_5x5_FLOAT,
|
||||
ASTC_6x5_FLOAT,
|
||||
ASTC_6x6_FLOAT,
|
||||
ASTC_8x5_FLOAT,
|
||||
ASTC_8x6_FLOAT,
|
||||
ASTC_8x8_FLOAT,
|
||||
ASTC_10x5_FLOAT,
|
||||
ASTC_10x6_FLOAT,
|
||||
ASTC_10x8_FLOAT,
|
||||
ASTC_10x10_FLOAT,
|
||||
ASTC_12x10_FLOAT,
|
||||
ASTC_12x12_FLOAT
|
||||
};
|
||||
|
||||
enum struct TextureUsageFlag : uint8
|
||||
{
|
||||
None = 0,
|
||||
Sampler = 1 << 0, // Textures supports sampling
|
||||
ColorTarget = 1 << 1, // Texture is color render target
|
||||
DepthStencilTarget = 1 << 2, // Texture is depth stencil target
|
||||
GraphicsStorageRead = 1 << 3, // Support Storage read at graphics stage
|
||||
ComputeStorageRead = 1 << 4, // Support Storage read at compute stage
|
||||
ComputeStorageWrite = 1 << 5, // Support Storage Write at compute stage
|
||||
ComputeStorageSimultaneousReadWrite =
|
||||
1 << 6, // Supports reads and writes in the same compute shader. Not equivalent to ComputeStorageRead | ComputeStorageWrite
|
||||
};
|
||||
|
||||
enum struct TextureType : uint8
|
||||
{
|
||||
Texture_2D,
|
||||
Texture_2DArray,
|
||||
Texture_3D,
|
||||
Texture_3DArray,
|
||||
Texture_Cube,
|
||||
Texture_CubeArray,
|
||||
};
|
||||
|
||||
enum struct TextureSampleCount : uint8
|
||||
{
|
||||
One,
|
||||
Two,
|
||||
Four,
|
||||
Eight,
|
||||
};
|
||||
|
||||
// Create Information structs
|
||||
struct TextureCreateInfo
|
||||
{
|
||||
TextureType Type;
|
||||
TextureFormat Format;
|
||||
TextureUsageFlag Flags;
|
||||
TextureSampleCount SampleCount;
|
||||
|
||||
uint32 Width;
|
||||
uint32 Height;
|
||||
union
|
||||
{
|
||||
uint32 LayerCount;
|
||||
uint32 Depth;
|
||||
}; // LayerCount is used in 2d array textures and Depth for 3d textures
|
||||
uint32 MipLevelCount;
|
||||
};
|
||||
|
||||
} // namespace Juliet
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <D3D12Texture.h>
|
||||
#include <pch.h>
|
||||
|
||||
#include <core/Memory/Allocator.h>
|
||||
|
||||
168
Juliet/src/Graphics/D3D12/D3D12Common.cpp
Normal file
168
Juliet/src/Graphics/D3D12/D3D12Common.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
#include <pch.h>
|
||||
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <Graphics/D3D12/D3D12Common.h>
|
||||
#include <Graphics/D3D12/DX12GraphicsDevice.h>
|
||||
#include <Graphics/D3D12/DX12Includes.h>
|
||||
#include <Graphics/D3D12/DX12Utils.h>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
namespace
|
||||
{
|
||||
constexpr size_t kStagingHeapDescriptorExpectedCount = 1024;
|
||||
|
||||
void InitStagingDescriptorPool(NonNullPtr<D3D12DescriptorHeap> heap, NonNullPtr<D3D12StagingDescriptorPool> pool)
|
||||
{
|
||||
for (uint32 idx = 0; idx < kStagingHeapDescriptorExpectedCount; ++idx)
|
||||
{
|
||||
pool->FreeDescriptors[idx].Pool = pool;
|
||||
pool->FreeDescriptors[idx].Heap = heap.Get();
|
||||
pool->FreeDescriptors[idx].CpuHandleIndex = idx;
|
||||
pool->FreeDescriptors[idx].CpuHandle.ptr = heap->DescriptorHeapCPUStart.ptr + (idx * heap->DescriptorSize);
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtendStagingDescriptorPool(NonNullPtr<D3D12Driver> driver, D3D12StagingDescriptorPool& pool)
|
||||
{
|
||||
D3D12DescriptorHeap* heap =
|
||||
CreateDescriptorHeap(driver, pool.Heaps[0]->HeapType, kStagingHeapDescriptorExpectedCount, true);
|
||||
if (!heap)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pool.HeapCount += 1;
|
||||
pool.Heaps = static_cast<D3D12DescriptorHeap**>(Realloc(pool.Heaps, pool.HeapCount * sizeof(D3D12DescriptorHeap*)));
|
||||
pool.Heaps[pool.HeapCount - 1] = heap;
|
||||
|
||||
pool.FreeDescriptorCapacity += kStagingHeapDescriptorExpectedCount;
|
||||
pool.FreeDescriptorCount += kStagingHeapDescriptorExpectedCount;
|
||||
pool.FreeDescriptors = static_cast<D3D12StagingDescriptor*>(
|
||||
Realloc(pool.FreeDescriptors, pool.FreeDescriptorCapacity * sizeof(D3D12StagingDescriptor)));
|
||||
|
||||
InitStagingDescriptorPool(heap, &pool);
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr<D3D12Driver> driver, D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count, bool isStaging)
|
||||
{
|
||||
ID3D12DescriptorHeap* handle;
|
||||
|
||||
auto heap = static_cast<D3D12DescriptorHeap*>(Calloc(1, sizeof(D3D12DescriptorHeap)));
|
||||
if (!heap)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
} // namespace Juliet::D3D12
|
||||
63
Juliet/src/Graphics/D3D12/D3D12Common.h
Normal file
63
Juliet/src/Graphics/D3D12/D3D12Common.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Common/NonNullPtr.h>
|
||||
#include <Core/Thread/Mutex.h>
|
||||
#include <Graphics/D3D12/DX12Includes.h>
|
||||
|
||||
// Definitions:
|
||||
// RTV = Render Target View
|
||||
// DSV = Depth Stencil View
|
||||
// SRV = Shader Resource View
|
||||
// UAV = Unordered Access View
|
||||
// CBV = Constant Buffer View
|
||||
|
||||
// Inspired (copy pasted a lot) by SDL GPU
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
struct D3D12Driver;
|
||||
// Forward declare
|
||||
struct D3D12StagingDescriptor;
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/direct3d12/descriptor-heaps
|
||||
struct D3D12DescriptorHeap
|
||||
{
|
||||
ID3D12DescriptorHeap* Handle;
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE HeapType;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE DescriptorHeapCPUStart;
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeapGPUStart; // only used by GPU heaps
|
||||
uint32 MaxDescriptors;
|
||||
uint32 DescriptorSize;
|
||||
uint32 CurrentDescriptorIndex; // only used by GPU heaps
|
||||
bool Staging : 1;
|
||||
};
|
||||
|
||||
struct D3D12StagingDescriptorPool
|
||||
{
|
||||
D3D12DescriptorHeap** Heaps;
|
||||
uint32 HeapCount;
|
||||
|
||||
// Descriptor handles are owned by resources, so these can be thought of as descriptions of a free index within a heap.
|
||||
uint32 FreeDescriptorCapacity;
|
||||
uint32 FreeDescriptorCount;
|
||||
D3D12StagingDescriptor* FreeDescriptors;
|
||||
};
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/direct3d12/descriptors-overview
|
||||
struct D3D12StagingDescriptor
|
||||
{
|
||||
D3D12StagingDescriptorPool* Pool;
|
||||
D3D12DescriptorHeap* Heap;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle;
|
||||
uint32 CpuHandleIndex;
|
||||
};
|
||||
|
||||
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);
|
||||
} // namespace Juliet::D3D12
|
||||
8
Juliet/src/Graphics/D3D12/D3D12Texture.cpp
Normal file
8
Juliet/src/Graphics/D3D12/D3D12Texture.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <pch.h>
|
||||
|
||||
#include <Graphics/D3D12/D3D12Texture.h>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
|
||||
}
|
||||
63
Juliet/src/Graphics/D3D12/D3D12Texture.h
Normal file
63
Juliet/src/Graphics/D3D12/D3D12Texture.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <Graphics/D3D12/D3D12Common.h>
|
||||
#include <Graphics/D3D12/DX12Includes.h>
|
||||
#include <Graphics/GraphicsDevice.h>
|
||||
|
||||
struct ID3D12Resource;
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
struct D3D12Texture;
|
||||
|
||||
struct D3D12ResourceHeap;
|
||||
|
||||
struct D3D12TextureContainer
|
||||
{
|
||||
TextureHeader Header;
|
||||
|
||||
D3D12Texture* ActiveTexture;
|
||||
D3D12Texture** Textures;
|
||||
uint32 Capacity;
|
||||
uint32 Count;
|
||||
|
||||
// Note: Swapchain images cannot be cycled
|
||||
bool CanBeCycled;
|
||||
|
||||
#if JULIET_DEBUG
|
||||
char* DebugName;
|
||||
#endif
|
||||
};
|
||||
|
||||
// D3D12 subresourcces: https://learn.microsoft.com/en-us/windows/win32/direct3d12/subresources (mipmaps, etc..)
|
||||
using D3D12TextureSubresource = struct D3D12TextureSubresource
|
||||
{
|
||||
D3D12Texture* Parent;
|
||||
uint32 Layer;
|
||||
uint32 Level;
|
||||
uint32 Depth;
|
||||
uint32 Index;
|
||||
|
||||
// One per depth slice
|
||||
D3D12StagingDescriptor* RTVHandles; // NULL if not a color target
|
||||
|
||||
D3D12StagingDescriptor UAVHandle; // NULL if not a compute storage write texture
|
||||
D3D12StagingDescriptor DSVHandle; // NULL if not a depth stencil target
|
||||
};
|
||||
|
||||
struct D3D12Texture
|
||||
{
|
||||
D3D12TextureContainer* Container;
|
||||
uint32 IndexInContainer;
|
||||
|
||||
ID3D12Resource* Resource;
|
||||
|
||||
D3D12TextureSubresource* Subresources;
|
||||
uint32 SubresourceCount; // Layer Count * number of Levels
|
||||
|
||||
D3D12StagingDescriptor SRVHandle;
|
||||
|
||||
// TODO: Should be atomic to support multithreading
|
||||
int32 RefCount;
|
||||
};
|
||||
} // namespace Juliet::D3D12
|
||||
@@ -167,6 +167,15 @@ namespace Juliet::D3D12
|
||||
|
||||
void DestroyDriver_Internal(NonNullPtr<D3D12Driver> driver)
|
||||
{
|
||||
for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1)
|
||||
{
|
||||
if (driver->StagingDescriptorPools[i])
|
||||
{
|
||||
DestroyStagingDescriptorPool(driver->StagingDescriptorPools[i]);
|
||||
driver->StagingDescriptorPools[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (driver->IndirectDrawCommandSignature)
|
||||
{
|
||||
ID3D12CommandSignature_Release(driver->IndirectDrawCommandSignature);
|
||||
@@ -240,7 +249,7 @@ namespace Juliet::D3D12
|
||||
|
||||
windowData->Window = window;
|
||||
|
||||
if (!CreateSwapChain(d3d12Driver, windowData))
|
||||
if (!CreateSwapChain(d3d12Driver, windowData, SwapChainComposition::SDR, PresentMode::VSync))
|
||||
{
|
||||
Log(LogLevel::Error, LogCategory::Graphics, "AttachToWindow failure: Cannot create Swap Chain.");
|
||||
Free(windowData);
|
||||
@@ -515,6 +524,20 @@ namespace Juliet::D3D12
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create 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));
|
||||
|
||||
if (driver->StagingDescriptorPools[i] == nullptr)
|
||||
{
|
||||
DestroyDriver_Internal(driver);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Assign Functions to the device
|
||||
device->DestroyDevice = DestroyGraphicsDevice;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Common/EnumUtils.h>
|
||||
#include <Graphics/D3D12/DX12Utils.h>
|
||||
#include <Graphics/D3D12/D3D12Common.h>
|
||||
#include <Graphics/D3D12/D3D12Texture.h>
|
||||
#include <Graphics/GraphicsDevice.h>
|
||||
|
||||
namespace Juliet
|
||||
@@ -17,10 +18,17 @@ namespace Juliet::D3D12
|
||||
{
|
||||
Window* Window;
|
||||
|
||||
IDXGISwapChain3* SwapChain;
|
||||
uint8 SwapChainTextureCount;
|
||||
IDXGISwapChain3* SwapChain;
|
||||
D3D12TextureContainer SwapChainTextureContainers[GPUDriver::kMaxFramesInFlight];
|
||||
DXGI_COLOR_SPACE_TYPE SwapChainColorSpace;
|
||||
SwapChainComposition SwapChainComposition;
|
||||
uint8 SwapChainTextureCount;
|
||||
|
||||
PresentMode PresentMode;
|
||||
|
||||
uint32 FrameCounter;
|
||||
uint32 Width;
|
||||
uint32 Height;
|
||||
};
|
||||
|
||||
struct D3D12Driver : GPUDriver
|
||||
@@ -56,6 +64,8 @@ namespace Juliet::D3D12
|
||||
D3D12CommandList** AvailableCommandLists;
|
||||
uint8 AvailableCommandListCapacity;
|
||||
|
||||
D3D12StagingDescriptorPool* StagingDescriptorPools[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES];
|
||||
|
||||
uint8 FramesInFlight;
|
||||
|
||||
bool IsTearingSupported : 1;
|
||||
|
||||
@@ -1,14 +1,140 @@
|
||||
#include <pch.h>
|
||||
|
||||
#include <Core/HAL/Display/Win32/Win32Window.h>
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <Graphics/D3D12/D3D12Texture.h>
|
||||
#include <Graphics/D3D12/DX12GraphicsDevice.h>
|
||||
#include <Graphics/D3D12/DX12Includes.h>
|
||||
#include <Graphics/D3D12/DX12SwapChain.h>
|
||||
#include <Graphics/D3D12/DX12Utils.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
bool CreateSwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData)
|
||||
namespace
|
||||
{
|
||||
DXGI_COLOR_SPACE_TYPE SwapchainCompositionToColorSpace[] = {
|
||||
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // SDR
|
||||
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // SDR_LINEAR
|
||||
DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709, // HDR_EXTENDED_LINEAR
|
||||
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 // HDR10_ST2084
|
||||
};
|
||||
|
||||
DXGI_FORMAT SwapchainCompositionToTextureFormat[] = {
|
||||
DXGI_FORMAT_B8G8R8A8_UNORM, // SDR
|
||||
DXGI_FORMAT_B8G8R8A8_UNORM, // SDR_LINEAR (NOTE: The RTV uses the sRGB format)
|
||||
DXGI_FORMAT_R16G16B16A16_FLOAT, // HDR_EXTENDED_LINEAR
|
||||
DXGI_FORMAT_R10G10B10A2_UNORM, // HDR10_ST2084
|
||||
};
|
||||
|
||||
TextureFormat SwapchainCompositionToJulietTextureFormat[] = {
|
||||
TextureFormat::B8G8R8A8_UNORM, // SDR
|
||||
TextureFormat::B8G8R8A8_UNORM_SRGB, // SDR_LINEAR
|
||||
TextureFormat::R16G16B16A16_FLOAT, // HDR_EXTENDED_LINEAR
|
||||
TextureFormat::R10G10B10A2_UNORM, // HDR10_ST2084
|
||||
};
|
||||
|
||||
bool CreateSwapChainTexture(NonNullPtr<D3D12Driver> driver, NonNullPtr<IDXGISwapChain3> swapChain,
|
||||
SwapChainComposition composition, NonNullPtr<D3D12TextureContainer> textureContainer, uint8 index)
|
||||
{
|
||||
ID3D12Resource* swapChainTexture = nullptr;
|
||||
HRESULT result =
|
||||
IDXGISwapChain_GetBuffer(swapChain, index, IID_ID3D12Resource, reinterpret_cast<void**>(&swapChainTexture));
|
||||
if (FAILED(result))
|
||||
{
|
||||
LogError(driver, "Cannot get buffer from SwapChain", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto texture = static_cast<D3D12Texture*>(Calloc(1, sizeof(D3D12Texture)));
|
||||
if (!texture)
|
||||
{
|
||||
LogError(driver, "Cannot allocate D3D12Texture (out of memory)", result);
|
||||
ID3D12Resource_Release(swapChainTexture);
|
||||
return false;
|
||||
}
|
||||
|
||||
texture->RefCount += 1;
|
||||
texture->SubresourceCount = 1;
|
||||
texture->Subresources = static_cast<D3D12TextureSubresource*>(Calloc(1, sizeof(D3D12TextureSubresource)));
|
||||
if (!texture->Subresources)
|
||||
{
|
||||
LogError(driver, "Cannot allocate D3D12TextureSubresource (out of memory)", result);
|
||||
Free(texture);
|
||||
ID3D12Resource_Release(swapChainTexture);
|
||||
return false;
|
||||
}
|
||||
texture->Subresources[0].RTVHandles =
|
||||
static_cast<D3D12StagingDescriptor*>(Calloc(1, sizeof(D3D12StagingDescriptor)));
|
||||
texture->Subresources[0].UAVHandle.Heap = nullptr;
|
||||
texture->Subresources[0].UAVHandle.Heap = nullptr;
|
||||
texture->Subresources[0].Parent = texture;
|
||||
texture->Subresources[0].Index = 0;
|
||||
texture->Subresources[0].Layer = 0;
|
||||
texture->Subresources[0].Depth = 1;
|
||||
texture->Subresources[0].Level = 0;
|
||||
|
||||
D3D12_RESOURCE_DESC textureDesc;
|
||||
ID3D12Resource_GetDesc(swapChainTexture, &textureDesc);
|
||||
textureContainer->Header.CreateInfo.Width = static_cast<uint32>(textureDesc.Width);
|
||||
textureContainer->Header.CreateInfo.Height = static_cast<uint32>(textureDesc.Height);
|
||||
textureContainer->Header.CreateInfo.LayerCount = 1;
|
||||
textureContainer->Header.CreateInfo.MipLevelCount = 1;
|
||||
textureContainer->Header.CreateInfo.Type = TextureType::Texture_2D;
|
||||
textureContainer->Header.CreateInfo.Flags = TextureUsageFlag::ColorTarget;
|
||||
textureContainer->Header.CreateInfo.SampleCount = TextureSampleCount::One;
|
||||
textureContainer->Header.CreateInfo.Format = SwapchainCompositionToJulietTextureFormat[ToUnderlying(composition)];
|
||||
|
||||
textureContainer->Textures = static_cast<D3D12Texture**>(Calloc(1, sizeof(D3D12Texture*)));
|
||||
if (!textureContainer->Textures)
|
||||
{
|
||||
Free(texture->Subresources);
|
||||
Free(texture);
|
||||
ID3D12Resource_Release(swapChainTexture);
|
||||
return false;
|
||||
}
|
||||
|
||||
textureContainer->Capacity = 1;
|
||||
textureContainer->Count = 1;
|
||||
textureContainer->Textures[0] = texture;
|
||||
textureContainer->ActiveTexture = texture;
|
||||
textureContainer->CanBeCycled = false;
|
||||
|
||||
texture->Container = textureContainer;
|
||||
texture->IndexInContainer = 0;
|
||||
|
||||
// Assign SRV to the swapchain texture
|
||||
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;
|
||||
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Texture2D.MipLevels = 1;
|
||||
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||
srvDesc.Texture2D.ResourceMinLODClamp = 0;
|
||||
srvDesc.Texture2D.PlaneSlice = 0;
|
||||
ID3D12Device_CreateShaderResourceView(driver->D3D12Device, swapChainTexture, &srvDesc, texture->SRVHandle.CpuHandle);
|
||||
|
||||
// Assign RTV to the swapchain texture
|
||||
DXGI_FORMAT swapchainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)];
|
||||
AssignStagingDescriptor(driver, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, texture->Subresources[0].RTVHandles[0]);
|
||||
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;
|
||||
rtvDesc.Format = (composition == SwapChainComposition::SDR_LINEAR) ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : swapchainFormat;
|
||||
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
|
||||
rtvDesc.Texture2D.MipSlice = 0;
|
||||
rtvDesc.Texture2D.PlaneSlice = 0;
|
||||
|
||||
ID3D12Device_CreateRenderTargetView(driver->D3D12Device, swapChainTexture, &rtvDesc,
|
||||
texture->Subresources[0].RTVHandles[0].CpuHandle);
|
||||
|
||||
ID3D12Resource_Release(swapChainTexture);
|
||||
|
||||
return true;
|
||||
}
|
||||
} // 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;
|
||||
@@ -18,9 +144,8 @@ namespace Juliet::D3D12
|
||||
return false;
|
||||
}
|
||||
|
||||
// SDR.
|
||||
// TODO: Not enough for HDR. but i have no way to test HDR easily except the steamdeck
|
||||
DXGI_FORMAT swapChainFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
// 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);
|
||||
|
||||
@@ -71,6 +196,11 @@ namespace Juliet::D3D12
|
||||
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))
|
||||
@@ -94,11 +224,40 @@ namespace Juliet::D3D12
|
||||
LogError(driver, "Failed to retrieve SwapChain descriptor", result);
|
||||
return false;
|
||||
}
|
||||
windowData->SwapChain = swapChain3;
|
||||
windowData->FrameCounter = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
void DestroySwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData) {}
|
||||
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 Juliet::D3D12
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace Juliet::D3D12
|
||||
struct D3D12Driver;
|
||||
struct D3D12WindowData;
|
||||
|
||||
extern bool CreateSwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData);
|
||||
extern bool CreateSwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData,
|
||||
SwapChainComposition composition, PresentMode presentMode);
|
||||
extern void DestroySwapChain(NonNullPtr<D3D12Driver> driver, NonNullPtr<D3D12WindowData> windowData);
|
||||
}
|
||||
} // namespace Juliet::D3D12
|
||||
|
||||
@@ -7,8 +7,6 @@ namespace Juliet
|
||||
{
|
||||
namespace
|
||||
{
|
||||
GraphicsDevice* CurrentGraphicsDevice = nullptr;
|
||||
|
||||
// TODO : IfDef new factories that are not compatible
|
||||
// Low chance of porting on something else than windows though. May be linux but will use vulkan that works on windows
|
||||
constexpr GraphicsDeviceFactory* Factories[] = { &DX12DeviceFactory };
|
||||
|
||||
@@ -3,16 +3,23 @@
|
||||
#include <Core/Common/NonNullPtr.h>
|
||||
#include <Graphics/Graphics.h>
|
||||
#include <Graphics/GraphicsConfig.h>
|
||||
#include <Graphics/Texture.h>
|
||||
|
||||
namespace Juliet
|
||||
{
|
||||
struct Window;
|
||||
|
||||
struct TextureHeader
|
||||
{
|
||||
TextureCreateInfo CreateInfo;
|
||||
};
|
||||
|
||||
struct GPUDriver
|
||||
{
|
||||
uint8 CommandListCount;
|
||||
|
||||
static constexpr uint8 kResourceBufferCount = 2;
|
||||
static constexpr uint8 kMaxFramesInFlight = 3;
|
||||
};
|
||||
|
||||
struct GraphicsDevice
|
||||
|
||||
Reference in New Issue
Block a user