// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Core/Delegate.h"
#include "Engine/Graphics/GPUResourceState.h"
#include "../IncludeDirectXHeaders.h"
#if GRAPHICS_API_DIRECTX12
class GPUResource;
class GPUContextDX12;
class GPUAsyncContextDX12;
///
/// Default amount of frames to wait until resource delete.
///
#define DX12_RESOURCE_DELETE_SAFE_FRAMES_COUNT 100
///
/// Custom resource state used to indicate invalid state (useful for debugging resource tracking issues).
///
#define D3D12_RESOURCE_STATE_CORRUPT (D3D12_RESOURCE_STATES)-1
///
/// Tracking of per-resource or per-subresource state for D3D12 resources that require to issue resource access barriers during rendering.
///
class ResourceStateDX12 : public GPUResourceState
{
public:
///
/// Returns true if resource state transition is needed in order to use resource in given state.
///
/// The current resource state.
/// the destination resource state.
/// True if need to perform a transition, otherwise false.
FORCE_INLINE static bool IsTransitionNeeded(D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES& after)
{
if (before == D3D12_RESOURCE_STATE_DEPTH_WRITE && after == D3D12_RESOURCE_STATE_DEPTH_READ)
return false;
if (after == D3D12_RESOURCE_STATE_COMMON)
return before != D3D12_RESOURCE_STATE_COMMON;
if (after == D3D12_RESOURCE_STATE_DEPTH_READ)
return ~(before & (D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)) == 0;
const D3D12_RESOURCE_STATES combined = before | after;
if ((combined & (D3D12_RESOURCE_STATE_GENERIC_READ | D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT)) == combined)
after = combined;
return before != after;
}
};
///
/// Base class for objects in DirectX 12 layer that can own a resource
///
class ResourceOwnerDX12
{
friend GPUContextDX12;
friend GPUAsyncContextDX12;
protected:
ID3D12Resource* _resource;
uint32 _subresourcesCount;
ResourceOwnerDX12()
: _resource(nullptr)
, _subresourcesCount(0)
{
}
~ResourceOwnerDX12()
{
}
public:
///
/// Action called on resource release event.
///
Delegate OnRelease;
///
/// The resource state tracking helper. Used for resource barriers.
///
ResourceStateDX12 State;
public:
///
/// Gets the subresources count.
///
FORCE_INLINE uint32 GetSubresourcesCount() const
{
return _subresourcesCount;
}
///
/// Gets DirectX 12 resource object handle
///
FORCE_INLINE ID3D12Resource* GetResource() const
{
return _resource;
}
///
/// Gets resource owner object as a GPUResource type or returns null if cannot perform cast.
///
virtual GPUResource* AsGPUResource() const = 0;
protected:
FORCE_INLINE void initResource(ID3D12Resource* resource, const D3D12_RESOURCE_STATES initialState, const D3D12_RESOURCE_DESC& desc, bool usePerSubresourceTracking = false)
{
initResource(resource, initialState, desc.DepthOrArraySize * desc.MipLevels, usePerSubresourceTracking);
}
void initResource(ID3D12Resource* resource, const D3D12_RESOURCE_STATES initialState, const uint32 subresourceCount, bool usePerSubresourceTracking = false);
void initResource(const D3D12_RESOURCE_STATES initialState, const uint32 subresourceCount, bool usePerSubresourceTracking = false);
void releaseResource(uint32 safeFrameCount = DX12_RESOURCE_DELETE_SAFE_FRAMES_COUNT);
};
#endif