I’m trying to apply a shader directly to the back buffer from C++ in a subsystem, so that I can apply processing to the texture of the scene and UI rendered together.
I’m currently binding to FSlateRenderer::OnBackBufferReadyToPresent, which is the last step before the render target is presented to the GPU as far as I can tell.
It’s almost working, I am just trying to do the most basic thing and run a pixel shader that just returns a solid color for now. And that color is appearing, but it is EXTREMELY glitchy. I’m not even sure where to begin debugging it.
I wish I could explain this better, but what I’m seeing is that in the top-right quadrant of the screen, a bunch of solid colored triangles are flickering in and out.
Here is the code:
void URenderSubsystem::BeginPIE( const bool bIsSimulating )
{
FSlateApplication::Get().GetRenderer()->OnBackBufferReadyToPresent().AddUObject( this, &URenderSubsystem::OnBackBufferReady_RenderThread );
}
void URenderSubsystem::OnBackBufferReady_RenderThread( SWindow& SlateWindow, const FTexture2DRHIRef& BackBuffer )
{
FGlobalShaderParams Params;
Params.Color = FVector4( 1, 0, 0, 1 );
FRHICommandListImmediate& RHICmdList = GRHICommandList.GetImmediateCommandList();
const FName TextureRenderTargetName = BackBuffer->GetName();
FMyGlobalShader::DrawColorToRenderTarget_RenderThread( RHICmdList, Params, TextureRenderTargetName, BackBuffer, ERHIFeatureLevel::SM5 );
}
// …
void FMyGlobalShader::DrawColorToRenderTarget_RenderThread(
FRHICommandListImmediate& RHICmdList,
const FGlobalShaderParams ShaderParams,
const FName& TextureRenderTargetName,
FTexture2DRHIRef OutTexture,
ERHIFeatureLevel::Type FeatureLevel)
{
check(IsInRenderingThread());
RHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, OutTexture);
FRHIRenderPassInfo RPInfo(OutTexture, ERenderTargetActions::DontLoad_Store, OutTexture);
RHICmdList.BeginRenderPass(RPInfo, TEXT("DrawColor"));
{
FIntPoint Res(OutTexture->GetSizeX(), OutTexture->GetSizeY());
RHICmdList.SetViewport(0, 0, 0.f, Res.X, Res.Y, 1.f);
FGlobalShaderMap* GlobalShaderMap = GetGlobalShaderMap(FeatureLevel);
TShaderMapRef< FGlobalShaderVS > VertexShader(GlobalShaderMap);
TShaderMapRef< FGlobalShaderPS > PixelShader(GlobalShaderMap);
FGraphicsPipelineStateInitializer Init;
RHICmdList.ApplyCachedRenderTargets(Init);
Init.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
Init.BlendState = TStaticBlendState<>::GetRHI();
Init.RasterizerState = TStaticRasterizerState<>::GetRHI();
Init.PrimitiveType = PT_TriangleList;
Init.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector4();
Init.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
Init.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
SetGraphicsPipelineState(RHICmdList, Init);
VertexShader->SetParameters(RHICmdList, VertexShader.GetVertexShader(), ShaderParams);
PixelShader->SetParameters(RHICmdList, PixelShader.GetPixelShader(), ShaderParams);
uint32 PrimitiveCount = kGridSubdivisionX * kGridSubdivisionY * 2;
RHICmdList.DrawPrimitive( 0, PrimitiveCount, 1 );
}
RHICmdList.EndRenderPass();
}
Hopefully this makes sense. Thanks!