How to use SceneRenderTask for multi-pass rendereing

Jan 9, 2015 at 6:54 PM
hi Jason,

I'm trying to do multi-pass rendering by subclassing SceneRenderTask class, as shown in sample projects related to deferred rendering.

My understand is that each SceneRenderTask subclass is vaguely equivalent to a render pass, i.e., it can be attached with its own vertex/pixel shader. I created a test project tutorial 8 to do a two pass rendering. It's a 2D drawing project. The first pass sample the loaded texture, the second pass manipulate the r value for each pixel in the right half image. But the code is not working. I got a black screen without any error message.

The first pass is just a ViewPerspective class. The second pass is done in TwoPassRenderer class, which create the render target for first pass and set that as the shader resource for second pass. Would you take a look on the code and see what's wrong with it? Appreciated for you help!
Jan 12, 2015 at 10:44 PM
I've updated the code to use a ViewPerspective subclass. Each render pass resets the render target and depth target. However, after the first render cycle, it gives a warning:
D3D11 WARNING: ID3D11DeviceContext::OMSetRenderTargets: Resource being set to OM RenderTarget slot 0 is still bound on input!

I tried various things in firstPassView without much success.
Jan 13, 2015 at 4:05 PM
The code is updated and working now, but still spit that warning message. I've tried things like:
void FirstPassView::ExecuteTask(PipelineManagerDX11* pPipelineManager, IParameterManager* pParamManager)
{
    // unbind the shader resource view
    ID3D11ShaderResourceView* srvs[1] = { 0 };
    pPipelineManager->GetDeviceContext()->PSSetShaderResources(m_RenderTarget->m_iResourceSRV, 1, srvs);
    ViewPerspective::ExecuteTask(pPipelineManager, pParamManager);
}
to unbind the render target of the first pass as the shader resource, but didn't work.
Coordinator
Jan 13, 2015 at 4:47 PM
Cool - I'm glad you got it up and running. I just downloaded the latest version of the code, and the issue is that you are using two render tasks and the final pass one is not 'unbinding' the resources that it is using. There are a number of ways to prevent this from happening, such as adding this code at the end of your TwoPassRenderer::ExecuteTask() method:
        pPipelineManager->ClearPipelineResources();
        pPipelineManager->ApplyPipelineResources();
That clears all SRVs from the pipeline on the engine side, and then applies the changes to the API. Unfortunately this results in more API calls, which is ok for a sample program, but isn't really necessary for more intensive code.

Another way around this issue is to enable the multithreading support on the renderer. This executes each render task on its own deferred context, and no pipeline state is inherited between task execution - and hence there will be no SRVs bound when you go back to the first pass again.

The method you showed above will work, but the first argument to the PSSetShaderResources method is incorrect. That first argument is the starting slot, and should not have the SRV index there. Replacing that with a 0 as the first argument will eliminate the warning:
void FirstPassView::ExecuteTask(PipelineManagerDX11* pPipelineManager, IParameterManager* pParamManager)
{
    // unbind the shader resource view
    ID3D11ShaderResourceView* srvs[1] = { 0 };
    pPipelineManager->GetDeviceContext()->PSSetShaderResources(0, 1, srvs);
    ViewPerspective::ExecuteTask(pPipelineManager, pParamManager);
}
Unfortunately, directly accessing the pipeline state like this will get the engine code out of synch with the API. What you could do is clear the pipeline state through the pipeline manager:
void FirstPassView::ExecuteTask(PipelineManagerDX11* pPipelineManager, IParameterManager* pParamManager)
{
    // unbind the shader resource view
    pPipelineManager->ClearPipelineState();
    ViewPerspective::ExecuteTask(pPipelineManager, pParamManager);
}
Marked as answer by wxz on 1/14/2015 at 11:15 AM