Files
2025-05-18 13:04:45 +08:00

303 lines
10 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "FxMaterial.h"
#include "ShaderParameters.h"
#include "Device/Device.h"
#include "EngineModule.h"
#include "RHIResourceUtils.h"
#include "TextureResource.h"
IMPLEMENT_GLOBAL_SHADER(VSH_Simple, "/Plugin/TextureGraph/Simple.usf", "VSH_Simple", SF_Vertex);
IMPLEMENT_GLOBAL_SHADER(FSH_Simple, "/Plugin/TextureGraph/Simple.usf", "FSH_Simple", SF_Pixel);
IMPLEMENT_GLOBAL_SHADER(FSH_SimpleVT, "/Plugin/TextureGraph/SimpleVT.usf", "FSH_SimpleVT", SF_Pixel);
//template <>
//void SetupDefaultParameters(FSH_Simple::FParameters& params)
//{
// FStandardSamplerStates_Setup(params.SamplerStates);
//}
//////////////////////////////////////////////////////////////////////////
FxMaterial::FxMaterial(TShaderRef<VSH_Base> VSH, TShaderRef<FSH_Base> FSH)
{
FString VSHHashStr = VSH->GetHash().ToString();
FString FSHHashStr = FSH->GetHash().ToString();
CHashPtr VSHHash = std::make_shared<CHash>(DataUtil::Hash((uint8*)&VSHHashStr.GetCharArray(), VSHHashStr.Len() * sizeof(TCHAR)), true);
CHashPtr FSHHash = std::make_shared<CHash>(DataUtil::Hash((uint8*)&FSHHashStr.GetCharArray(), FSHHashStr.Len() * sizeof(TCHAR)), true);
CHashPtrVec Hashes = { VSHHash, FSHHash };
HashValue = CHash::ConstructFromSources(Hashes);
}
FxMaterial::FxMaterial(TShaderRef<VSH_Base> VSH)
{
FString VSHHashStr = VSH->GetHash().ToString();
CHashPtr VSHHash = std::make_shared<CHash>(DataUtil::Hash((uint8*)&VSHHashStr.GetCharArray(), VSHHashStr.Len() * sizeof(TCHAR)), true);
CHashPtrVec Hashes = { VSHHash };
HashValue = CHash::ConstructFromSources(Hashes);
}
FxMaterial::FxMaterial(FString VSHHashStr, FString FSHHashStr)
{
CHashPtr VSHHash = std::make_shared<CHash>(DataUtil::Hash((uint8*)&VSHHashStr.GetCharArray(), VSHHashStr.Len() * sizeof(TCHAR)), true);
CHashPtr FSHHash = std::make_shared<CHash>(DataUtil::Hash((uint8*)&FSHHashStr.GetCharArray(), FSHHashStr.Len() * sizeof(TCHAR)), true);
CHashPtrVec Hashes = { VSHHash, FSHHash };
HashValue = CHash::ConstructFromSources(Hashes);
}
std::unique_ptr<FxMaterial::MemberLUT>& FxMaterial::GetParamsLUT()
{
if (ParamsLUT)
return ParamsLUT;
ParamsLUT = std::make_unique<MemberLUT>();
FxMetadataSet MetadataSet = GetMetadata();
for (FxMetadata& MetaInfo : MetadataSet)
{
const TArray<FShaderParametersMetadata::FMember>& members = MetaInfo.Metadata->GetMembers();
char* base = MetaInfo.StartAddress;
for (size_t MemberIndex = 0; MemberIndex < members.Num(); MemberIndex++)
{
const FShaderParametersMetadata::FMember& Member = members[MemberIndex];
FName memberName = Member.GetName();
MemberInfo MemInfo = { Member, base + Member.GetOffset() };
ParamsLUT->Add(memberName, MemInfo);
}
}
return ParamsLUT;
}
FxMaterial::MemberInfo FxMaterial::GetMember(FName MemberName)
{
auto& paramsLUT = GetParamsLUT();
/// Now find the Member
MemberInfo* MemInfo = paramsLUT->Find(MemberName);
check(MemInfo != nullptr);
return *MemInfo;
}
void FxMaterial::SetArrayTextureParameterValue(FName Name, const ArrayTexture& Value)
{
auto MemInfo = GetMember(Name);
const FShaderParametersMetadata::FMember& Member = MemInfo.Member;
char* Arg = MemInfo.RawPtr;
check(Arg);
UE_LOG(LogDevice, VeryVerbose, TEXT("Bind Array Texture: %s"), *Name.ToString());
//memcpy(Arg, (const char*)&tex, sizeof(FRHITexture**));
/// We actually bind all of these when we're actually rendering
Textures.push_back({ Name, Arg, nullptr, Value });
}
void FxMaterial::SetTextureParameterValue(FName Name, const UTexture* Value)
{
auto MemInfo = GetMember(Name);
const FShaderParametersMetadata::FMember& Member = MemInfo.Member;
char* Arg = MemInfo.RawPtr;
check(Arg);
UE_LOG(LogDevice, VeryVerbose, TEXT("Bind Texture: %s"), *Name.ToString());
//memcpy(Arg, (const char*)&tex, sizeof(FRHITexture**));
/// We actually bind all of these when we're actually rendering
Textures.push_back({ Name, Arg, Value });
}
void FxMaterial::BindTexturesForBlitting()
{
for (auto& BoundTex : Textures)
{
if (BoundTex.Texture)
{
check(BoundTex.Texture->GetResource());
FRHITexture* tex = BoundTex.Texture->GetResource()->TextureRHI;
check(tex);
FRHITexture* texture2DArray = tex->GetTexture2DArray();
if (!texture2DArray)
{
memcpy(BoundTex.Arg, (const char*)&tex, sizeof(FRHITexture**));
}
else
{
memcpy(BoundTex.Arg, (const char*)&texture2DArray, sizeof(FRHITexture**));
}
}
else if (BoundTex.tiles.size())
{
auto DestArg = BoundTex.Arg;
for (const auto& ti : BoundTex.tiles)
{
FRHITexture* TextureRHI = ti->GetResource()->TextureRHI;
memcpy(DestArg, (const char*)&TextureRHI, sizeof(FRHITexture**));
DestArg += sizeof(FRHITexture**) ;
}
}
}
}
void FxMaterial::SetScalarParameterValue(FName Name, float Value)
{
auto MemInfo = GetMember(Name);
const FShaderParametersMetadata::FMember& Member = MemInfo.Member;
check(Member.GetNumColumns() == 1 && Member.GetNumRows() == 1 && Member.GetBaseType() == EUniformBufferBaseType::UBMT_FLOAT32);
float* Arg = reinterpret_cast<float*>(MemInfo.RawPtr);
check(Arg);
*Arg = Value;
}
void FxMaterial::SetScalarParameterValue(FName Name, int32 Value)
{
auto MemInfo = GetMember(Name);
const FShaderParametersMetadata::FMember& Member = MemInfo.Member;
check(Member.GetNumColumns() == 1 && Member.GetNumRows() == 1 && Member.GetBaseType() == EUniformBufferBaseType::UBMT_INT32);
int* Arg = reinterpret_cast<int*>(MemInfo.RawPtr);
check(Arg);
*Arg = Value;
}
void FxMaterial::SetVectorParameterValue(FName Name, const FLinearColor& Value)
{
auto MemInfo = GetMember(Name);
const FShaderParametersMetadata::FMember& Member = MemInfo.Member;
/// We only support RGBA/XYZW vectors right now. This is to avoid
/// trying to write 4 float values to something that isn't the
/// correct size
check(Member.GetNumColumns() <= 4 && Member.GetBaseType() == EUniformBufferBaseType::UBMT_FLOAT32);
FLinearColor* Arg = reinterpret_cast<FLinearColor*>(MemInfo.RawPtr);
check(MemInfo.RawPtr);
memcpy(MemInfo.RawPtr, (const void*)&Value, sizeof(float) * Member.GetNumColumns());
}
void FxMaterial::SetVectorParameterValue(FName Name, const FIntVector4& Value)
{
auto MemInfo = GetMember(Name);
const FShaderParametersMetadata::FMember& Member = MemInfo.Member;
/// We support int32 XYZW vectors in this function. This is to avoid
/// trying to write 4 Int values to something that isn't the
/// correct size
check(Member.GetNumColumns() <= 4 && Member.GetBaseType() == EUniformBufferBaseType::UBMT_INT32);
FIntVector4* Arg = reinterpret_cast<FIntVector4*>(MemInfo.RawPtr);
check(MemInfo.RawPtr);
memcpy(MemInfo.RawPtr, (const void*)&Value, sizeof(float) * Member.GetNumColumns());
}
void FxMaterial::SetStructParameterValue(FName Name, const char* Value, size_t StructSize)
{
size_t memberPosition = 0;
auto MemInfo = GetMember(Name);
char* Arg = reinterpret_cast<char*>(MemInfo.RawPtr);
auto InputSize = MemInfo.Member.GetStructMetadata()->GetSize() ;
check(StructSize == InputSize)
memcpy(Arg, Value, InputSize);
}
void FxMaterial::SetArrayParameterValue(FName Name, const char* startAddress, size_t TypeSize, size_t ArraySize)
{
auto MemInfo = GetMember(Name);
auto Member = MemInfo.Member;
char* Arg = MemInfo.RawPtr;
check(Arg);
uint32 MemberSize = Member.GetMemberSize();
uint32 ElementSize = TypeSize;
uint32 ExpandingRange = MemberSize / ElementSize;
uint32 Skip = ExpandingRange > 0 ? ArraySize/ExpandingRange : 0;
int ValueIndex = 0;
for (uint32 i = 0; i < ExpandingRange;i += Skip)
{
check(ValueIndex < ArraySize)
if(ValueIndex < ArraySize)
{
memcpy(Arg + (i * ElementSize), startAddress + (ValueIndex * ElementSize), ElementSize);
ValueIndex++;
}
}
}
void FxMaterial::SetMatrixParameterValue(FName Name, const FMatrix& Value)
{
auto MemInfo = GetMember(Name);
const FShaderParametersMetadata::FMember& Member = MemInfo.Member;
/// Must be the correct size and dimension
check(Member.GetNumColumns() == 4 && Member.GetNumRows() == 4 && Member.GetBaseType() == EUniformBufferBaseType::UBMT_FLOAT32);
FMatrix* Arg = reinterpret_cast<FMatrix*>(MemInfo.RawPtr);
check(Arg);
*Arg = Value;
}
bool FxMaterial::DoesMemberExist(FName MemberName)
{
auto& ParamsLUTObj = GetParamsLUT();
/// Now find the Member
auto* MemInfo = ParamsLUTObj->Find(MemberName);
return (MemInfo != nullptr);
}
//////////////////////////////////////////////////////////////////////////
void QuadScreenBuffer::InitRHI(FRHICommandListBase& RHICmdList)
{
//FVertexDeclarationElementList Elements;
//uint16 Stride = sizeof(FFilterVertex);
//Elements.Add(FVertexElement(0, STRUCT_OFFSET(FFilterVertex, Position), VET_Float4, 0, Stride));
//Elements.Add(FVertexElement(0, STRUCT_OFFSET(FFilterVertex, UV), VET_Float2, 1, Stride));
//VertexDeclarationRHI = PipelineStateCache::GetOrCreateVertexDeclaration(Elements);
const FFilterVertex Vertices[] =
{
FFilterVertex { FVector4f(-1, 1, 0, 1), FVector2f(0, 0) },
FFilterVertex { FVector4f( 1, 1, 0, 1), FVector2f(1, 0) },
FFilterVertex { FVector4f(-1,-1, 0, 1), FVector2f(0, 1) },
FFilterVertex { FVector4f( 1,-1, 0, 1), FVector2f(1, 1) },
};
VertexBufferRHI = UE::RHIResourceUtils::CreateVertexBufferFromArray(RHICmdList, TEXT("FxMaterial_VB"), EBufferUsageFlags::Static, MakeConstArrayView(Vertices));
}
//////////////////////////////////////////////////////////////////////////
TGlobalResource<QuadScreenBuffer> FxMaterial::GQuadBuffer;
void FxMaterial::InitPSO_Default(FGraphicsPipelineStateInitializer& PSO)
{
PSO.BlendState = TStaticBlendState<>::GetRHI();
PSO.RasterizerState = TStaticRasterizerState<>::GetRHI();
PSO.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
PSO.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
PSO.PrimitiveType = PT_TriangleStrip;
}
void FxMaterial::InitPSO_Default(FGraphicsPipelineStateInitializer& PSO, FRHIVertexShader* VSH, FRHIPixelShader* FSH)
{
InitPSO_Default(PSO);
PSO.BoundShaderState.VertexShaderRHI = VSH;
PSO.BoundShaderState.PixelShaderRHI = FSH;
}
//////////////////////////////////////////////////////////////////////////