Hi
I’m trying to run an Async function from the render thread. The ultimate goal is to get the FColor array from a URenderTarget2d (UTexture).
A LARGE amount of the code had been copied from the Export Render blueprint node. Currently i’ve been able to get the FColor and do what i need to do with it. The reason i’ve copied a lot of the code from Export Render is because it’s largely doing what i needed to do which was to get the UTexture to an array, but as it stands it immediately exports the array to an image saving to disk.
Ultimately my code runs a function which is using the macro “ENQUEUE_RENDER_COMMAND”. This whole function is called every frame and it’s called by multiple actors as well. But so far testing with a single actor and i go from 70fps to fps in the high 20s. So with the requirement of multiple different actors running the same node/function every frame. It’s not really possible.
Here’s the section of code that’s being run within the macro and therefore on the render thread.
bool URenderExportFunc::ResolvePixelData(UTexture* InTexture, const FOnPixelsReady& OnPixelsReady){
FTextureResource* TextureResource = InTexture->GetResource();
ENQUEUE_RENDER_COMMAND(ResolvePixelData)(
[TextureResource, OnPixelsReady](FRHICommandListImmediate& RHICmdList)
{
{...}
TArray<FColor> RawPixels;
RawPixels.SetNum(SourceRect.Width() * SourceRect.Height());
RHICmdList.ReadSurfaceData(Texture2D, SourceRect, RawPixels, ReadDataFlags);
TUniquePtr<TImagePixelData<FColor>> PixelData = MakeUnique<TImagePixelData<FColor>>(SourceRect.Size(), TArray64<FColor>(MoveTemp(RawPixels)));
OnPixelsReady(MoveTemp(PixelData));
}
The “RHICmdList.ReadSurfaceData” is running horrendously slow and hoping i can run the block of code async off the renderthread. The OnPixelsReady is a lambda function that will process and deal with the render to then export the data else where. I have no need for the UTexture/Image after this point. So if it’s possible to run the whole chunk async then clean up after it self. I assumed after the async was done that the data would get garbage collected.
I attempted to create an async task
FGraphEventRef MyTask = FFunctionGraphTask::CreateAndDispatchWhenReady([&]()
{
TArray<FColor> RawPixels;
RawPixels.SetNum(SourceRect.Width() * SourceRect.Height());
RHICmdList.ReadSurfaceData(Texture2D, SourceRect, RawPixels, ReadDataFlags);
TUniquePtr<TImagePixelData<FColor>> PixelData = MakeUnique<TImagePixelData<FColor>>(SourceRect.Size(), TArray64<FColor>(MoveTemp(RawPixels)));
// Notify the main thread when the task is done (if needed)
// You can use a delegate or a custom mechanism to signal the completion of this task.
}, TStatId(), nullptr, ENamedThreads::AnyThread);
When i try to run this i run into this check.
void FRHICommandListImmediate::ExecuteAndReset()
{
check(IsInRenderingThread());
Are there any suggestions on how i can accomplish what i’m trying to do which is get the UTexture to an FColor to then run my lambda function “OnPixelsReady”. I know that the “RHICmdList.ReadSurfaceData” is what’s causing the issue as i had commented everything under it (including the OnPixelsReady) and it started to impact performance. With it commented out there’s no performance issue.