#pragma once

#include <Core/Common/NonNullPtr.h>
#include <Core/Thread/Mutex.h>
#include <Graphics/D3D12/D3D12DescriptorHeap.h>
#include <Graphics/D3D12/D3D12Includes.h>

// Definitions:
// RTV = Render Target View
// DSV = Depth Stencil View
// SRV = Shader Resource View
// UAV = Unordered Access View
// CBV = Constant Buffer View
// PSO = Pipeline State Object

// Inspired (copy pasted a lot) by SDL GPU
namespace Juliet::D3D12
{
    // Forward declare
    struct D3D12Driver;
    struct D3D12StagingDescriptor;

    struct D3D12StagingDescriptorPool
    {
        Arena*                          Arena;
        Internal::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;
        Internal::D3D12DescriptorHeap* Heap;
        D3D12_CPU_DESCRIPTOR_HANDLE    CpuHandle;
        uint32                         CpuHandleIndex;
    };

    namespace Internal
    {
        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
