Hi everyone,
I noticed a performance issue caused by blueprints while working with big structures.
In particular, calling a UFUNCTION that accepts a USTRUCT as an input parameter creates a copy of the structure before using it.
This behavior is present in Blueprint, but is absent when calling the function from code.
This is a snippet (with a small structure) used to reproduce the issue:
`#pragma once
include “CoreMinimal.h”
include “Kismet/BlueprintFunctionLibrary.h”
include “ExampleBlueprintFunctionLibrary.generated.h”
USTRUCT(BlueprintType)
struct FExampleStruct
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 ExampleValue = 0;
FExampleStruct()
{
UE_LOG(LogTemp, Log, TEXT(“%s”), StringCast(FUNCTION).Get());
}
FExampleStruct(const FExampleStruct& Other)
: ExampleValue(Other.ExampleValue)
{
UE_LOG(LogTemp, Log, TEXT(“%s”), StringCast(FUNCTION).Get());
}
FExampleStruct(FExampleStruct&& Other)
: ExampleValue(Other.ExampleValue)
{
UE_LOG(LogTemp, Log, TEXT(“%s”), StringCast(FUNCTION).Get());
}
FExampleStruct& operator=(const FExampleStruct& Other)
{
UE_LOG(LogTemp, Log, TEXT(“%s”), StringCast(FUNCTION).Get());
if (this == &Other)
return *this;
ExampleValue = Other.ExampleValue;
return *this;
}
FExampleStruct& operator=(FExampleStruct&& Other)
{
UE_LOG(LogTemp, Log, TEXT(“%s”), StringCast(FUNCTION).Get());
if (this == &Other)
return *this;
ExampleValue = Other.ExampleValue;
return *this;
}
};
UCLASS()
class EXAMPLERUNTIME_API UExampleBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
UFUNCTION(BlueprintCallable)
static int32 GetExampleValue(const FExampleStruct& InStruct)
{
UE_LOG(LogTemp, Log, TEXT(“%s”), StringCast(FUNCTION).Get());
return InStruct.ExampleValue;
}
UFUNCTION(BlueprintCallable)
static void SetExampleValue(UPARAM(Ref) FExampleStruct& InStruct, const int32 InValue)
{
UE_LOG(LogTemp, Log, TEXT(“%s”), StringCast(FUNCTION).Get());
InStruct.ExampleValue = InValue;
}
};`
This is the Blueprint calls to reproduce the issue:
[Image Removed]
And this is the OutputLog that shows the behaviour:
LogBlueprintUserMessages: [ExampleActor_C_1] BP Pre SetExampleValue - 0 LogTemp: FExampleStruct::FExampleStruct LogTemp: FExampleStruct::operator = LogTemp: UExampleBlueprintFunctionLibrary::SetExampleValue LogBlueprintUserMessages: [ExampleActor_C_1] BP Post SetExampleValue - 1 LogBlueprintUserMessages: [ExampleActor_C_1] BP Pre GetExampleValue - 1 LogTemp: FExampleStruct::FExampleStruct LogTemp: FExampleStruct::operator = LogTemp: UExampleBlueprintFunctionLibrary::GetExampleValue LogBlueprintUserMessages: [ExampleActor_C_1] BP Post GetExampleValue - 1
Is this the intended behaviour of structs (to be always copied when a UFUNCTION is called from Blueprints)?
This is causing performance issues in our projects.
Thank you in advance,
Lorenzo