#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 WaitUntilGPUIsIdle(NonNullPtr<GPUDriver> driver);
    extern bool Wait(NonNullPtr<GPUDriver> driver, bool waitForAll, Fence* const* fences,
                     uint32 numFences JULIET_DEBUG_PARAM(String querier));
    extern bool QueryFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
    extern void ReleaseFence(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence JULIET_DEBUG_PARAM(String querier));

    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 JULIET_DEBUG_PARAM(String querier));
        extern void        DestroyFence(NonNullPtr<D3D12Fence> fence);
    } // namespace Internal
} // namespace Juliet::D3D12
