FTexture2DRHIRef clarification

Hello,
I need to use this kind of texture, I can create one but then how I can fill it with data? for example all black elements?
There is a good written documentation or simple example about this type? I’m using C++

FTexture2DRHIRef InputTexture = NULL;
FRHIResourceCreateInfo CreateInfo;
InputTexture = RHICreateTexture2D(dim_x, dim_x, PF_R32_UINT, 1, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);

thanks everybody for your attention.

There you go:



FRHIResourceCreateInfo CreateInfo;
FTexture2DRHIRef Texture2D = RHICreateTexture2D(1, 1, PF_R32_UINT, 1, 1, TexCreate_ShaderResource, CreateInfo);
TextureRHI = Texture2D;

// Write the contents of the texture.
uint32 DestStride;
uint32* DestBuffer = (uint32*)RHILockTexture2D(Texture2D, 0, RLM_WriteOnly, DestStride, false);

FMemory::Memcpy(DestBuffer,SourceBuffer,sizeof(uint32)*BufferSize);
RHIUnlockTexture2D(Texture2D, 0, false)


Also remember that all of the operations above must be executed on the rendering thread.

Hello lion032,
I really appreciate your help. I used this code similiar to the one you suggested but my the ue4 crashes… Did I miss something?


		FRHIResourceCreateInfo CreateInfo;
		InputTexture = RHICreateTexture2D(960, 540, PF_R32_UINT, 1, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
		// Write the contents of the texture.
		uint32 DestStride;
		uint32* DestBuffer = (uint32*)RHILockTexture2D(InputTexture, 0, RLM_WriteOnly, DestStride, false);
		int BufferSize = 960 * 540 * 4;
		uint8 * SourceBuffer = new uint8[BufferSize];
		for (int i = 0; i < BufferSize; i++) {
			SourceBuffer* = 255;
		}
		FMemory::Memcpy(DestBuffer, SourceBuffer, BufferSize);
		RHIUnlockTexture2D(InputTexture, 0, false);

How I can be sure I’m executing this code inside the rendering thread? I’m calling this code inside the Tick() function of an actor.

1 Like

Ok, I found out that I should use this macro in order to be sure the code will be executed in the rendering thread:
ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER

But, at this point, what parameter should I pass to these macro? I see 4 parameters are needed plus the code.

Using this code seems to not crash, can someone help me to understand the macro parameter?


		ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(void, FTexture2DRHIRef, InputTexture, InputTexture ,
			{	
				FRHIResourceCreateInfo CreateInfo;
				InputTexture = RHICreateTexture2D(960, 540, PF_R32_UINT, 1, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
				// Write the contents of the texture.
				uint32 DestStride;
				uint32* DestBuffer = (uint32*)RHILockTexture2D(InputTexture, 0, RLM_WriteOnly, DestStride, false);
				int BufferSize = 960 * 540 * 4;
				uint8 * SourceBuffer = new uint8[BufferSize];
				for (int i = 0; i < BufferSize; i++) {
					SourceBuffer* = 255;
				}
				FMemory::Memcpy(DestBuffer, SourceBuffer, BufferSize);
				RHIUnlockTexture2D(InputTexture, 0, false);
			}
		);

because I’m not sure about what I’ve done

Actor’s tick function happens on game thread so calling those functions there is not allowed and that is the reason for the crash.
To send something to the rendering thread you must enqueue it.
This is done as follows:



//Create Texture
ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(
	FCreateActorsTexure,
	FTexture2DRHIRef,TexurePtr,InputTexture,
	{
		FRHIResourceCreateInfo CreateInfo;
		TexurePtr = RHICreateTexture2D(960, 540, PF_R32_UINT, 1, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
	}
);

//Update Texture
uint32 BufferSize = 960 * 540 * 4;
uint8 * SourceBuffer = new uint8[BufferSize];

for (int i = 0; i < BufferSize; i++) 
{
	SourceBuffer* = 255;
}

ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER(
	FUpdateActorsTexure,
	FTexture2DRHIRef,TexurePtr,InputTexture,
	uint8*, NewData,SourceBuffer,
	uint32, Size,BufferSize,
	{
		uint32 DestStride;
		uint32* DestBuffer = (uint32*)RHILockTexture2D(TexurePtr, 0, RLM_WriteOnly, DestStride, false);
		FMemory::Memcpy(DestBuffer, NewData, Size);
		RHIUnlockTexture2D(TexurePtr, 0, false);
		delete ] NewData;
	}
);


#define ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(TypeName,ParamType1,ParamName1,ParamValue1,Code)

TypeName - Arbitrary name of the render command
ParamType1 - The type of the parameter
ParamName1 - Name of the parameter inside the render command
ParamValue1 - the value of the parameter passed from the outside
Code- The code that will be executed on the render thread

thank you again, now I underestand better the macro and I have a better general view about the environment.

only, I hope, the last issue:
I just tried your code, It crash…

I commented the last part



ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER(
	FUpdateActorsTexure,
	FTexture2DRHIRef,TexurePtr,InputTexture,
	uint8*, NewData,SourceBuffer,
	uint32, Size,BufferSize,
	{
		uint32 DestStride;
		uint32* DestBuffer = (uint32*)RHILockTexture2D(TexurePtr, 0, RLM_WriteOnly, DestStride, false);
		FMemory::Memcpy(DestBuffer, NewData, Size);
		RHIUnlockTexture2D(TexurePtr, 0, false);
		delete ] NewData;
	}
);

And it does not crash anymore. So there is something mysterious here. Ideas?

Can you provide an error output?

when it crash it tells me that
“You do not have any debugging symbols required to display the callstack for this crash.”

I did a fast google search and I found that I must download the 10GB (ouch!) stuff regarding debug symbols. I’m doing this right now.

Can I provide you other usefull information in the meantime?

[POST EDITED]
After some trial and error the code above seems working and It was a problem of mine. I didn’t understand what it was… I’m quite confused but now It does not crash.

Add a member variable
FRenderCommandFence Fence;

Before the update texture comment add

Fence.BeginFence();

and after the loop add

Fence.Wait();

[EDIT AGAIN]

I think I’ve found out the problem

now it crash again

here my code:


			 FTexture2DRHIRef InputTexture = NULL;

		/*if (ComputeShading) {
			    ComputeShading->ExecuteComputeShader(TotalElapsedTime);
				InputTexture = ComputeShading->GetTexture(); //This is the output texture from the compute shader that we will pass to the pixel shader.
			}*/

			//ComputeShaderBlend = FMath::Clamp(ComputeShaderBlend +  ComputeShaderBlendScalar * DeltaSeconds, 0.0f, 1.0f);

			 //MY STUFF
			 //Create Texture
			FRenderCommandFence Fence;

			Fence.BeginFence();
			Fence.Wait();
			ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(FCreateActorsTexure,
				FTexture2DRHIRef, TexurePtr, InputTexture,
				{
					FRHIResourceCreateInfo CreateInfo;
					TexurePtr = RHICreateTexture2D(960, 540, PF_R32_UINT, 1, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
					FRHICommandListImmediate& RHICmdList = GRHICommandList.GetImmediateCommandList();
					RHICmdList.ClearColorTexture(TexurePtr, FLinearColor::Red, FIntRect());
				}
			);

			
			//Update Texture
			uint32 BufferSize = 960 * 540 * 4;
			uint8 * SourceBuffer = new uint8[BufferSize];

			for (uint32 i = 0; i < BufferSize; i++)
			{
				SourceBuffer* = 20;
			}
			Fence.Wait();

			ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER(FUpdateActorsTexure,
				FTexture2DRHIRef, TexurePtr, InputTexture,
				uint8*, NewData, SourceBuffer,
				uint32, Size, BufferSize,
				{
					uint32 DestStride;
					uint32* DestBuffer = (uint32*)RHILockTexture2D(TexurePtr, 0, RLM_WriteOnly, DestStride, false);
					FMemory::Memcpy(DestBuffer, NewData, Size);
					RHIUnlockTexture2D(TexurePtr, 0, false);
					delete] NewData;
				}
			);


if I comment like above



/*if (ComputeShading) {
			    ComputeShading->ExecuteComputeShader(TotalElapsedTime);
				InputTexture = ComputeShading->GetTexture(); //This is the output texture from the compute shader that we will pass to the pixel shader.
			}*/


it crashes!

I put a screenshot so you can see in which line it crashes

It would be nice for me to not call the commented line!
So I want just to create a texture manually like you suggested.
I’m becoming crazy about this :confused:

Move the fence begin and wait to after the creation