Files
UnrealEngine/Engine/Source/Runtime/D3D12RHI/Private/D3D12Texture.h
2025-05-18 13:04:45 +08:00

284 lines
11 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
D3D12Texture.h: Implementation of D3D12 Texture
=============================================================================*/
#pragma once
#include "D3D12CommandList.h"
#include "D3D12Resources.h"
#include "D3D12View.h"
/** If true, guard texture creates with SEH to log more information about a driver crash we are seeing during texture streaming. */
#define GUARDED_TEXTURE_CREATES (PLATFORM_WINDOWS && !(UE_BUILD_SHIPPING || UE_BUILD_TEST || PLATFORM_COMPILER_CLANG))
// @todo don't make global here!
void SafeCreateTexture2D(FD3D12Device* pDevice,
FD3D12Adapter* Adapter,
const FD3D12ResourceDesc& TextureDesc,
const D3D12_CLEAR_VALUE* ClearValue,
FD3D12ResourceLocation* OutTexture2D,
FD3D12BaseShaderResource* Owner,
EPixelFormat Format,
ETextureCreateFlags Flags,
D3D12_RESOURCE_STATES InitialState,
const TCHAR* Name);
/** D3D12 RHI Texture class */
class FD3D12Texture : public FRHITexture, public FD3D12BaseShaderResource, public FD3D12LinkedAdapterObject<FD3D12Texture>
{
public:
// Static helper functions
static bool CanBe4KAligned(const FD3D12ResourceDesc& Desc, EPixelFormat UEFormat);
FD3D12Texture() = delete;
/** Initialization constructor. */
FD3D12Texture(
const FRHITextureCreateDesc& InDesc,
class FD3D12Device* InParent)
: FRHITexture(InDesc)
, FD3D12BaseShaderResource(InParent) {}
virtual ~FD3D12Texture();
// IRefCountedObject interface overrides from FD3D12BaseShaderResource
virtual FReturnedRefCountValue AddRef() const override { return FReturnedRefCountValue{FRHIResource::AddRef()}; }
virtual uint32 Release() const override { return FRHIResource::Release(); }
virtual uint32 GetRefCount() const override { return FRHIResource::GetRefCount(); }
// FRHIResource overrides
#if RHI_ENABLE_RESOURCE_INFO
bool GetResourceInfo(FRHIResourceInfo& OutResourceInfo) const override;
#endif
// FRHITexture overrides
#if D3D12RHI_USE_DUMMY_BACKBUFFER
virtual void* GetTextureBaseRHI() override { return this; }
#else
virtual void* GetTextureBaseRHI() override final { return this; }
#endif
virtual void* GetNativeResource() const override final;
virtual FRHIDescriptorHandle GetDefaultBindlessHandle() const override;
// Accessors.
bool IsStreamable() const { return EnumHasAnyFlags(GetDesc().Flags, ETextureCreateFlags::Streamable); }
bool SkipsFastClearFinalize() const { return EnumHasAnyFlags(GetDesc().Flags, ETextureCreateFlags::NoFastClearFinalize); }
const FTextureRHIRef& GetAliasingSourceTexture() const { return AliasingSourceTexture; }
void GetReadBackHeapDesc(D3D12_PLACED_SUBRESOURCE_FOOTPRINT& OutFootprint, uint32 Subresource) const;
bool HasCreatedRTVsPerSlice() const
{
return bCreatedRTVsPerSlice;
}
bool HasRenderTargetViews() const { return (RenderTargetViews.Num() > 0); }
TConstArrayView<TSharedPtr<FD3D12RenderTargetView>> GetRenderTargetViews() const { return TConstArrayView<TSharedPtr<FD3D12RenderTargetView>>(RenderTargetViews); }
FD3D12ShaderResourceView* GetShaderResourceView() const { return ShaderResourceView.Get(); }
FD3D12RenderTargetView* GetRenderTargetView(int32 MipIndex, int32 ArraySliceIndex) const;
FD3D12DepthStencilView* GetDepthStencilView(FExclusiveDepthStencil AccessType) const { return DepthStencilViews[AccessType.GetIndex()].Get(); }
#if PLATFORM_REQUIRES_TYPELESS_RESOURCE_DISCARD_WORKAROUND
bool GetRequiresTypelessResourceDiscardWorkaround() const { return bRequiresTypelessResourceDiscardWorkaround; }
#endif // #if PLATFORM_REQUIRES_TYPELESS_RESOURCE_DISCARD_WORKAROUND
// Setup functionality
void UploadInitialData(FRHICommandListBase& RHICmdList, FD3D12ResourceLocation&& SourceLocation, D3D12_RESOURCE_STATES DestinationState);
void CreateViews(FD3D12Texture* FirstLinkedObject);
void SetCreatedRTVsPerSlice(bool Value, int32 InRTVArraySize)
{
bCreatedRTVsPerSlice = Value;
RTVArraySizePerMip = InRTVArraySize;
}
void SetNumRTVs(int32 Num)
{
RenderTargetViews.SetNum(Num);
}
void EmplaceRTV(D3D12_RENDER_TARGET_VIEW_DESC const& RTVDesc, int32 Index, FD3D12Texture* FirstLinkedObject)
{
check(RenderTargetViews.IsValidIndex(Index));
check(!RenderTargetViews[Index]);
RenderTargetViews[Index] = MakeShared<FD3D12RenderTargetView>(GetParentDevice(), FirstLinkedObject ? FirstLinkedObject->RenderTargetViews[Index].Get() : nullptr);
RenderTargetViews[Index]->CreateView(this, RTVDesc);
}
void EmplaceDSV(D3D12_DEPTH_STENCIL_VIEW_DESC const& DSVDesc, int32 Index, FD3D12Texture* FirstLinkedObject)
{
check(Index < FExclusiveDepthStencil::MaxIndex);
check(!DepthStencilViews[Index]);
DepthStencilViews[Index] = MakeShared<FD3D12DepthStencilView>(GetParentDevice(), FirstLinkedObject ? FirstLinkedObject->DepthStencilViews[Index].Get() : nullptr);
DepthStencilViews[Index]->CreateView(this, DSVDesc);
}
void EmplaceSRV(D3D12_SHADER_RESOURCE_VIEW_DESC const& SRVDesc, FD3D12Texture* FirstLinkedObject)
{
check(!ShaderResourceView);
FD3D12ShaderResourceView::EFlags Flags = SkipsFastClearFinalize()
? FD3D12ShaderResourceView::EFlags::SkipFastClearFinalize
: FD3D12ShaderResourceView::EFlags::None;
ShaderResourceView = MakeShared<FD3D12ShaderResourceView>(GetParentDevice(), FirstLinkedObject ? FirstLinkedObject->ShaderResourceView.Get() : nullptr);
ShaderResourceView->CreateView(this, SRVDesc, Flags);
}
// Locking/update functions
FRHILockTextureResult Lock(FRHICommandListBase& RHICmdList, const FRHILockTextureArgs& Arguments);
void Unlock(FRHICommandListBase& RHICmdList, const FRHILockTextureArgs& Arguments);
void UpdateTexture2D(FRHICommandListBase& RHICmdList, uint32 MipIndex, const struct FUpdateTextureRegion2D& UpdateRegion, uint32 SourcePitch, const uint8* SourceData);
void UpdateTexture(FD3D12CommandContext& Context, uint32 MipIndex, uint32 DestX, uint32 DestY, uint32 DestZ, const D3D12_TEXTURE_COPY_LOCATION& SourceCopyLocation);
void CopyTextureRegion(FD3D12CommandContext& Context, uint32 DestX, uint32 DestY, uint32 DestZ, FD3D12Texture* SourceTexture, const D3D12_BOX& SourceBox);
// Resource aliasing
void AliasResources(FD3D12Texture* Texture);
void SetAliasingSource(FTextureRHIRef& SourceTextureRHI) { AliasingSourceTexture = SourceTextureRHI; }
// Staging buffer reuse
void ReuseStagingBuffer(TUniquePtr<FD3D12LockedResource>&& LockedResource, uint32 Subresource);
protected:
// A shader resource view of the texture.
TSharedPtr<FD3D12ShaderResourceView> ShaderResourceView;
// Set when RTVs are created for each slice - TexCreate_TargetArraySlicesIndependently for TextureArrays & Cubemaps
bool bCreatedRTVsPerSlice{ false };
#if PLATFORM_REQUIRES_TYPELESS_RESOURCE_DISCARD_WORKAROUND
bool bRequiresTypelessResourceDiscardWorkaround = false;
#endif // #if PLATFORM_REQUIRES_TYPELESS_RESOURCE_DISCARD_WORKAROUND
// Number of RTVs per mip when stored per slice
int32 RTVArraySizePerMip{};
// A render targetable view of the texture.
TArray<TSharedPtr<FD3D12RenderTargetView>, TInlineAllocator<1>> RenderTargetViews;
// A depth-stencil targetable view of the texture.
TSharedPtr<FD3D12DepthStencilView> DepthStencilViews[FExclusiveDepthStencil::MaxIndex];
// Data for each subresource while texture is locked
TMap<uint32, TUniquePtr<FD3D12LockedResource>> LockedMap;
// Cached footprint size of first resource - optimization
mutable TUniquePtr<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> FirstSubresourceFootprint;
// Source texture when aliased
FTextureRHIRef AliasingSourceTexture;
};
inline FD3D12RenderTargetView* FD3D12Texture::GetRenderTargetView(int32 MipIndex, int32 ArraySliceIndex) const
{
int32 ArrayIndex = MipIndex;
if (bCreatedRTVsPerSlice)
{
check(ArraySliceIndex >= 0);
ArrayIndex = MipIndex * RTVArraySizePerMip + ArraySliceIndex;
check(ArrayIndex < RenderTargetViews.Num());
}
else
{
// Catch attempts to use a specific slice without having created the texture to support it
check(ArraySliceIndex == -1 || ArraySliceIndex == 0);
}
if (ArrayIndex < RenderTargetViews.Num())
{
return RenderTargetViews[ArrayIndex].Get();
}
return 0;
}
template<>
struct TD3D12ResourceTraits<FRHITexture>
{
typedef FD3D12Texture TConcreteType;
};
class FD3D12Viewport;
#if D3D12RHI_USE_DUMMY_BACKBUFFER
class FD3D12BackBufferReferenceTexture2D : public FD3D12Texture
{
public:
FD3D12BackBufferReferenceTexture2D(const FRHITextureCreateDesc& InDesc, FD3D12Viewport* InViewPort, FD3D12Device* InDevice)
: FD3D12Texture(InDesc, InDevice)
, Viewport(InViewPort)
{
}
FD3D12Viewport* GetViewPort() const { return Viewport; }
FRHITexture* GetBackBufferTexture() const;
virtual FRHIDescriptorHandle GetDefaultBindlessHandle() const override;
// FRHITexture overrides
virtual void* GetTextureBaseRHI() override { return (void*)GetBackBufferTexture(); }
private:
FD3D12Viewport* const Viewport;
};
#endif
/** Given a pointer to a RHI texture that was created by the D3D12 RHI, returns a pointer to the FD3D12Texture it encapsulates. */
FORCEINLINE FD3D12Texture* GetD3D12TextureFromRHITexture(FRHITexture* Texture)
{
if (!Texture)
{
return NULL;
}
FRHITexture* RHITexture = Texture;
FD3D12Texture* Result((FD3D12Texture*)RHITexture->GetTextureBaseRHI());
check(Result);
return Result;
}
FORCEINLINE FD3D12Texture* GetD3D12TextureFromRHITexture(FRHITexture* Texture, uint32 GPUIndex)
{
FD3D12Texture* Result = GetD3D12TextureFromRHITexture(Texture);
if (Result != nullptr)
{
Result = Result->GetLinkedObject(GPUIndex);
check(Result);
return Result;
}
else
{
return Result;
}
}
namespace FD3D12TextureStats
{
// Note: This function can be called from many different threads
// @param TextureSize >0 to allocate, <0 to deallocate
// @param b3D true:3D, false:2D or cube map
// @param bStreamable true:Streamable, false:not streamable
void UpdateD3D12TextureStats(FD3D12Texture& Texture, const FD3D12ResourceDesc& ResourceDesc, const FRHITextureDesc& TextureDesc, uint64 TextureSize, bool bNewTexture, bool bAllocating);
void D3D12TextureAllocated(FD3D12Texture& Texture);
void D3D12TextureDeleted(FD3D12Texture& Texture);
};
namespace UE::D3D12RHI::TextureUtils
{
// Fills in the ClearValue argument based on the ResourceDesc and CreateDesc flags.
D3D12_CLEAR_VALUE* FillClearValue(D3D12_CLEAR_VALUE& ClearValue, const FD3D12ResourceDesc& ResourceDesc, const FRHITextureDesc& TextureDesc);
void ReconcileInitialState(FRHICommandListBase& RHICmdList, FD3D12Texture* Texture, D3D12_RESOURCE_STATES CurrentState, D3D12_RESOURCE_STATES NeededState);
uint64 CalculateResourceSize(FD3D12Texture* Texture);
void CopyBulkData(void* UploadMemory, uint64 UploadMemorySize, FD3D12Texture* Texture, FResourceBulkDataInterface* BulkData);
D3D12_PLACED_SUBRESOURCE_FOOTPRINT GetInitializerSubresourceFootprint(FD3D12Texture* Texture, uint32 Subresource, uint32& NumRows);
}