Community Tutorial: Simple compute shader with CPU readback

In this tutorial, we’ll create and dispatch our very own compute shader from C++ and BP!

This tutorial is extracted from Bare-bones Compute Shader in UE5 | Compute | Shadeup

https://dev.epicgames.com/community/learning/tutorials/WkwJ/unreal-engine-simple-compute-shader-with-cpu-readback

6 Likes

I love it! thank you very much.
I didn’t get to integrate it yet to my project, but will do so in the following days.
There seems to be just one error (again not sure because I didn’t implement) in the ‘Calling from cpp’ part:
“FMySimpleComputeShaderInterface::DispatchRenderThread”
The function should be called inside Disaptch() which call a few lines later. is this a copy-paste error?
Also, it was called with no brackets, inputs and semicolon which makes it more suspicious.

Ah, yes, that’s a copy-paste error, I’ve removed it. Thanks for pointing that out.

Best of luck with the integration! If you run into any problems with the code feel free to reply here and I’ll do my best to help.

I got it up and running! thank you! this is a very good guide
I do have some remarks:

  1. since I used my own name for the plugin, files, etc., I had to do some modifications. While changing things I got a runtime error about my .usf mapping, I fixed already though. My issue was that when calling IMPLEMENT_GLOBAL_SHADER I used just my shader folder name, instead of the virtual directory name local shader location.
    It would be best to change to this:
// This will tell the engine to create the shader and where the shader entry point is.
//                            ShaderType                            ShaderVirtualPath/ShaderLocalPath                     Shader function name    Type
IMPLEMENT_GLOBAL_SHADER(FMySimpleComputeShader, "/Plugin/MyShaders/MySimpleComputeShader.usf", "MySimpleComputeShader", SF_Compute);

And the virtual mapping part as well accordingly

	FString PluginShaderDir = FPaths::Combine(IPluginManager::Get().FindPlugin(TEXT("%YourPlugin%"))->GetBaseDir(), TEXT("Shaders/Private"));
	AddShaderSourceDirectoryMapping(TEXT("/Plugin/MyShader"), PluginShaderDir);
  1. I’m not sure what’s the purpose of the additional header file MySimpleComputeShader.h, I was able to work without it, just move the defines to the cpp.

  2. in the .cs you’re checking twice for Target.bBuildEditor == true. it would be best to move all the logic to a single one, just for the sake of order.

1 Like

Thanks for putting this together!

I’m rather new to UE and C++ in general, but I’m not quite sure from the tutorial how to capture the output from the dispatch() function. Trying to capture ‘OutputVal’ directly from the lambda is returning zero (as below). Or should I be trying to extract data from Params?


int OutputTmp = 0;
// Executes the compute shader and calls the TFunction when complete.
FMySimpleComputeShaderInterface::Dispatch(Params, [&OutputTmp](int OutputVal) {
	//	// Called when the results are back from the GPU.
	OutputTmp = OutputVal;
	GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, FString::Printf(TEXT("OutputVal= %d"), OutputTmp)); // Returns 10
	});

GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, FString::Printf(TEXT("OutputTmp= %d"), OutputTmp)); // Returns 0

Edit : Ah, I think it may be that the code doesn’t wait for dispatch to finish, and so the later debug statement can execute before the function gets called to set OutputTmp. If I initialize OutputTmp as a class variable then the following seems to give me what I expect.


// Executes the compute shader and calls the TFunction when complete.
FMySimpleComputeShaderInterface::Dispatch(Params, [this](int OutputVal) {
	//	// Called when the results are back from the GPU.
	OutputTmp = OutputVal;
	GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, FString::Printf(TEXT("OutputVal= %d"), OutputTmp)); // Returns 10
	});

GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, FString::Printf(TEXT("OutputTmp= %d"), OutputTmp)); // Returns 10, maybe not on the first try

Thanks to sharing
I love UE5.1 and compute shader
I have difficult to compile under win10 and launch project without issues

Writing to a render target

Writing to a render target | Compute | Shadeup
Do you have tested under UE5.1 please ?

Hello my friend, first of all, thank you so much for the tutorial and plugins,
i’ve been looking for how to write compute shaders for a long time.
and second, the 2 plugins that have materials don’t work and return the error message:
“The compute shader has a problem”.
which means ComputeShader is not created correctly, and bIsShaderValid is false.

And then there is the render target plugins, they throw warnings in compilation:

1 - ExampleComputeShader.cpp(159): warning C4996: ‘FMeshPassProcessorRenderState::SetViewUniformBuffer’: SetViewUniformBuffer is deprecated. Use View.ViewUniformBuffer and bind on an RDG pass instead. Please update your code to the new API before upgrading to the next release, otherwise your project will no longer compile.

2 - ExampleComputeShader.cpp(176): warning C4996: ‘FRHIComputeCommandList::SetComputeShader’: ComputePipelineStates should be used instead of direct ComputeShaders. You can use SetComputePipelineState(RHICmdList, ComputeShader). Please update your code to the new API before upgrading to the next release, otherwise your project will no longer compile.

The second is easy to fix, it says how, but the first one got me completely clueless, i tried all plugins on 5.0.3 and 5.1, so i turn to you and hope you know the the solution.


Apologies for the late reply.

This is something that I neglected to mention in the docs but please make sure the material has the following:

  1. Material domain of Surface
  2. Blend mode of Opaque
  3. Shading model of DefaultLit
  4. Used With Virtual HeightfieldMesh enabled in the details panel

After that please click apply, if there are any errors please screenshot and share here (they should show up in the output panel)

image
image

Thank you for the reply, i tried your settings with Material Evaluation plugin, i still get the same error “The compute shader has a problem” and no error in the output log, but when i try it a second time Unreal crashes and i get this error:

LoginId:653723684a9aff1b98870b9be38a30e5
EpicAccountId:

Fatal error: [File:D:\build\++UE5\Sync\Engine\Source\Runtime\D3D12RHI\Private\D3D12Commands.cpp] [Line: 1663] Shader expected a uniform buffer at slot 0 but got null instead (Shader='' UB='View'). Rendering code needs to set a valid uniform buffer for this slot.

UnrealEditor_D3D12RHI
UnrealEditor_D3D12RHI
UnrealEditor_ComputeShader!FRHICommand<FRHICommandDispatchComputeShader,FRHICommandDispatchComputeShaderString>::ExecuteAndDestruct() [F:\UNREAL ENGINE\UE_5.1\Engine\Source\Runtime\RHI\Public\RHICommandList.h:855]
UnrealEditor_RHI
UnrealEditor_RHI
UnrealEditor_RHI
UnrealEditor_Core
UnrealEditor_Core
UnrealEditor_RenderCore
UnrealEditor_Core
UnrealEditor_Core
kernel32
ntdll

and for the Material to Render Target Plugin, same error “The compute shader has a problem” but no crash, and no error in the output log, take your time to find a fix, thank you again.



1st is Material evaluation, 2nd is Material to render target.

you know what, i have used computer shaders using various platforms and game engines, but this looks way more complex than making compute shaders in open gl from scratch to be honest. idk why unreal has to be like this

Hey there, I have been trying to implement this into my unreal project. However, I seem to be running into 2 issues. Firstly, I am trying to add the files from inside visual studio, and when I add them everything seems to be fine. However, once I rebuild uproject visual studio files to get intelliSense up to date, everything I just added disappears. I assume it is related to the module not being recognized and requiring a extra step. Secondly, visual studio doesn’t allow me to create a second .h file with the same name.

I was wondering I you solved this, and if u worked from visual studio as well.
Greetings, GT

so yeah: creating it from Visual Studio is the problem. Creating it in explorer → deleting Binaries & Intermediates → recreating VS files = files dont disappear.

there are also some include statement that have changed, adding Runtime/ infront fixes it:
“Runtime/Renderer/Private/ScenePrivate.h”
“Runtime/RenderCore/Public/RenderGraphUtils.h”
“MyShaders/Public/MySimpleComputeShader.h”

1 Like

Consent

Basicly, Compute Shader is just data parralel method. You can achieve this even just using simple vert/frag shader.

I am new to UE but I have some experiences about Compute Shader and RT and OpenCL/GL/MP when I work in simulation.

I feel it’s even easy to use three.js+opengl to do ping-pong method render target.