ShaderParameters.h
/** A shader parameter's register binding. e.g. float1/2/3/4, can be an array, UAV */
class FShaderParameter
{
DECLARE_EXPORTED_TYPE_LAYOUT(FShaderParameter, RENDERCORE_API, NonVirtual);
public:
FShaderParameter()
: BufferIndex(0)
, BaseIndex(0)
, NumBytes(0)
{}
RENDERCORE_API void Bind(const FShaderParameterMap& ParameterMap,const TCHAR* ParameterName, EShaderParameterFlags Flags = SPF_Optional);
friend RENDERCORE_API FArchive& operator<<(FArchive& Ar,FShaderParameter& P);
bool IsBound() const { return NumBytes > 0; }
inline bool IsInitialized() const
{
return true;
}
uint32 GetBufferIndex() const { return BufferIndex; }
uint32 GetBaseIndex() const { return BaseIndex; }
uint32 GetNumBytes() const { return NumBytes; }
private:
LAYOUT_FIELD(uint16, BufferIndex);
LAYOUT_FIELD(uint16, BaseIndex);
// 0 if the parameter wasn't bound
LAYOUT_FIELD(uint16, NumBytes);
};
ShaderParameters.cpp
void FShaderParameter::Bind(const FShaderParameterMap& ParameterMap,const TCHAR* ParameterName,EShaderParameterFlags Flags)
{
if (!ParameterMap.FindParameterAllocation(ParameterName,BufferIndex,BaseIndex,NumBytes) && Flags == SPF_Mandatory)
{
if (!UE_LOG_ACTIVE(LogShaders, Log))
{
UE_LOG(LogShaders, Fatal,TEXT("Failure to bind non-optional shader parameter %s! The parameter is either not present in the shader, or the shader compiler optimized it out."),ParameterName);
}
else
{
// We use a non-Slate message box to avoid problem where we haven't compiled the shaders for Slate.
FPlatformMisc::MessageBoxExt( EAppMsgType::Ok, *FText::Format(
NSLOCTEXT("UnrealEd", "Error_FailedToBindShaderParameter", "Failure to bind non-optional shader parameter {0}! The parameter is either not present in the shader, or the shader compiler optimized it out. This will be an assert with LogShaders suppressed!"),
FText::FromString(ParameterName)).ToString(), TEXT("Warning"));
}
}
}
FArchive& operator<<(FArchive& Ar,FShaderParameter& P)
{
uint16& PBufferIndex = P.BufferIndex;
return Ar << P.BaseIndex << P.NumBytes << PBufferIndex;
}
bool FShaderParameterMap::FindParameterAllocation(const TCHAR* ParameterName,uint16& OutBufferIndex,uint16& OutBaseIndex,uint16& OutSize) const
{
const FParameterAllocation* Allocation = ParameterMap.Find(ParameterName);
if(Allocation)
{
OutBufferIndex = Allocation->BufferIndex;
OutBaseIndex = Allocation->BaseIndex;
OutSize = Allocation->Size;
if (Allocation->bBound)
{
// Can detect copy-paste errors in binding parameters. Need to fix all the false positives before enabling.
//UE_LOG(LogShaders, Warning, TEXT("Parameter %s was bound multiple times. Code error?"), ParameterName);
}
Allocation->bBound = true;
return true;
}
else
{
return false;
}
}