Files
UnrealEngineUWP/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateMaterialResource.cpp
aurel cordonnier e3f7878676 Merge from Release-Engine-Test @ 17462327 to UE5/Main
This represents UE4/Main @17430120 and Dev-PerfTest @17437669

[CL 17463546 by aurel cordonnier in ue5-main branch]
2021-09-08 16:42:26 -04:00

192 lines
5.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SlateMaterialResource.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "Styling/SlateBrush.h"
namespace SlateMaterialResource
{
#if SLATE_CHECK_UOBJECT_RENDER_RESOURCES
void CheckInvalidUMaterial(const UMaterialInterface& InMaterialResource, const FName& InDebugName)
{
if (GSlateCheckUObjectRenderResources)
{
bool bIsValidLowLevel = InMaterialResource.IsValidLowLevelFast(false);
if (!bIsValidLowLevel || !IsValid(&InMaterialResource) || InMaterialResource.GetClass() == UMaterialInterface::StaticClass())
{
UE_LOG(LogSlate, Error, TEXT("Material '%s' is not valid. PendingKill:'%d'. ValidLowLevelFast:'%d'. InvalidClass:'%d'")
, *InDebugName.ToString()
, (bIsValidLowLevel ? !IsValid(&InMaterialResource) : false)
, bIsValidLowLevel
, (bIsValidLowLevel ? InMaterialResource.GetClass() == UMaterialInterface::StaticClass() : false));
const TCHAR* Message = TEXT("We detected an invalid resource in FSlateMaterialResource. Check the log for more detail.");
if (GSlateCheckUObjectRenderResourcesShouldLogFatal)
{
UE_LOG(LogSlate, Fatal, TEXT("%s"), Message);
}
else
{
ensureAlwaysMsgf(false, TEXT("%s"), Message);
}
}
}
}
void CheckInvalidMaterialProxy(const FMaterialRenderProxy* MaterialProxy, const FName& InDebugName)
{
if (GSlateCheckUObjectRenderResources)
{
if (MaterialProxy == nullptr || MaterialProxy->IsDeleted() || MaterialProxy->IsMarkedForGarbageCollection())
{
UE_LOG(LogSlate, Error, TEXT("Material '%s' Render Proxy is: nullptr:'%d'. Deleted:'%d'. Marked for GC:'%d'")
, *InDebugName.ToString()
, (MaterialProxy == nullptr)
, (MaterialProxy ? MaterialProxy->IsDeleted() : false)
, (MaterialProxy ? MaterialProxy->IsMarkedForGarbageCollection() : false));
const TCHAR* Message = TEXT("We detected an invalid resource render proxy in FSlateMaterialResource. Check the log for more detail.");
if (GSlateCheckUObjectRenderResourcesShouldLogFatal)
{
UE_LOG(LogSlate, Fatal, TEXT("%s"), Message);
}
else
{
ensureAlwaysMsgf(false, TEXT("%s"), Message);
}
}
}
}
#endif
}
FSlateMaterialResource::FSlateMaterialResource(const UMaterialInterface& InMaterialResource, const FVector2D& InImageSize, FSlateShaderResource* InTextureMask )
: MaterialObject( &InMaterialResource)
, SlateProxy( new FSlateShaderResourceProxy )
, TextureMaskResource( InTextureMask )
, Width(FMath::RoundToInt(InImageSize.X))
, Height(FMath::RoundToInt(InImageSize.Y))
{
#if SLATE_CHECK_UOBJECT_RENDER_RESOURCES
SlateMaterialResource::CheckInvalidUMaterial(InMaterialResource, NAME_None);
MaterialProxy = InMaterialResource.GetRenderProxy();
MaterialObjectWeakPtr = MaterialObject;
UpdateMaterialName();
SlateMaterialResource::CheckInvalidMaterialProxy(MaterialProxy, DebugName);
#else
MaterialProxy = InMaterialResource.GetRenderProxy();
#endif
SlateProxy->ActualSize = InImageSize.IntPoint();
SlateProxy->Resource = this;
if (MaterialProxy && (MaterialProxy->IsDeleted() || MaterialProxy->IsMarkedForGarbageCollection()))
{
MaterialProxy = nullptr;
}
}
FSlateMaterialResource::~FSlateMaterialResource()
{
if (SlateProxy)
{
delete SlateProxy;
}
}
void FSlateMaterialResource::UpdateMaterial(const UMaterialInterface& InMaterialResource, const FVector2D& InImageSize, FSlateShaderResource* InTextureMask)
{
#if SLATE_CHECK_UOBJECT_RENDER_RESOURCES
SlateMaterialResource::CheckInvalidUMaterial(InMaterialResource, DebugName);
MaterialObject = &InMaterialResource;
MaterialProxy = InMaterialResource.GetRenderProxy();
MaterialObjectWeakPtr = MaterialObject;
UpdateMaterialName();
SlateMaterialResource::CheckInvalidMaterialProxy(MaterialProxy, DebugName);
#else
MaterialObject = &InMaterialResource;
MaterialProxy = InMaterialResource.GetRenderProxy();
#endif
if (MaterialProxy && (MaterialProxy->IsDeleted() || MaterialProxy->IsMarkedForGarbageCollection()))
{
MaterialProxy = nullptr;
}
if (!SlateProxy)
{
SlateProxy = new FSlateShaderResourceProxy;
}
TextureMaskResource = InTextureMask;
SlateProxy->ActualSize = InImageSize.IntPoint();
SlateProxy->Resource = this;
Width = FMath::RoundToInt(InImageSize.X);
Height = FMath::RoundToInt(InImageSize.Y);
}
void FSlateMaterialResource::ResetMaterial()
{
MaterialObject = nullptr;
MaterialProxy = nullptr;
#if SLATE_CHECK_UOBJECT_RENDER_RESOURCES
MaterialObjectWeakPtr = nullptr;
UpdateMaterialName();
#endif
TextureMaskResource = nullptr;
if (SlateProxy)
{
delete SlateProxy;
}
SlateProxy = nullptr;
Width = 0;
Height = 0;
}
#if SLATE_CHECK_UOBJECT_RENDER_RESOURCES
void FSlateMaterialResource::UpdateMaterialName()
{
const UMaterialInstanceDynamic* MID = Cast<UMaterialInstanceDynamic>(MaterialObject);
if(MID && MID->Parent)
{
// MID's don't have nice names. Get the name of the parent instead for tracking
DebugName = MID->Parent->GetFName();
}
else if(MaterialObject)
{
DebugName = MaterialObject->GetFName();
}
else
{
DebugName = NAME_None;
}
}
void FSlateMaterialResource::CheckForStaleResources() const
{
if (DebugName != NAME_None)
{
// pending kill objects may still be rendered for a frame so it is valid for the check to pass
const bool bEvenIfPendingKill = true;
// This test needs to be thread safe. It doesn't give us as many chances to trap bugs here but it is still useful
const bool bThreadSafe = true;
checkf(MaterialObjectWeakPtr.IsValid(bEvenIfPendingKill, bThreadSafe), TEXT("Material %s has become invalid. This means the resource was garbage collected while slate was using it"), *DebugName.ToString());
}
}
#endif