Sign in to follow this  
WOsborn

MRT Postprocessing Question

Recommended Posts

WOsborn    137
I have written a postprocessing filter system like the one in ShaderX5 8.1 'Postprocessing Effects in Design' p.463 The system consists of Filters->Phases->Steps.
FILTER Generic:
PHASE 1:
step 1> SetRenderTargets:
            DX9_DEV->SetRenderTarget( 0, pSurfaceA );
	    DX9_DEV->SetDepthStencilSurface( _screenA_depth_surface );
            DX9_DEV->SetRenderTarget( 1, pSurfaceB );
step 2> Clear:
            DX9_DEV->Clear(Color | Depth)   //(clears both targets??)
step 3> Render Scene:
            Render grid and a hedra mesh using pixel shader that looks like this..

---------------------
struct MRT_Out
{
	float4 RT0 : COLOR0;
	float4 RT1 : COLOR1;
};
MRT_Out basicTextured(basic_vOut IN)  // pixel shader
{
    MRT_Out OUT = (MRT_Out)0;
    OUT.RT0 = float4( 1,0,0, 1.0 );
    OUT.RT1 = float4( 0,0,1, 1.0 );	
    return OUT;	
}



If you look at the accompanying images you'll see NVPerfHUD showing the second render target is available, but it is not being rendered to. Shouldnt pSurfaceB have a blue hedra in it? What am I missing, or what could I be missing?? I have checked CAPS. Click image for larger view. Draw Scene Grid PerfHud Image 1 Draw Hedra Object ( notice only renderes red to 1st RT and no blue in 2nd PerfHud Image 2 Other Views in PerfHUD PerfHud Image 3 PerfHud Image 4 [Edited by - WOsborn on August 8, 2007 7:50:37 AM]

Share this post


Link to post
Share on other sites
remigius    1172
Well, the way you generally go about it sounds fine. Without exact code it's going to be hard to try and figure out what might be going wrong though. And what kind of graphics card are you using?

Share this post


Link to post
Share on other sites
WOsborn    137
Card: NV 6800 GT 256

Of Course the hedra object has that pixel shader from above applied to it.

From what i've seen from the Pixel motion blur demo this is all that needs to be done?!

Essentially this is what is happening in the steps...

Phase 1:
H = DX9_DEV->SetRenderTarget( 0, _surf_RENDA );
H = DX9_DEV->SetDepthStencilSurface( _surf_RENDA_depth_surface );
H = DX9_DEV->SetRenderTarget( 1, _surf_RENDB );
-----
H = DX9_DEV->Clear( 0,
NULL,
Color | Depth,
D3DCOLOR_COLORVALUE( 0,0,0, 1 ),
1,
0 );
-----
Render();

Phase 2:

H = DX9_DEV->SetRenderTarget( 1, NULL );
H = DX9_DEV->SetRenderTarget( 0, screen_OUT );
H = DX9_DEV->SetDepthStencilSurface( _screen_depth_surface );
-----
H = DX9_DEV->Clear( 0,
NULL,
Color | Depth,
D3DCOLOR_COLORVALUE( 0,0,0, 1 ),
1,
0 );
-----
Draw_Quad_Using_BufferA();








This is how the config file looks to give an overview of what is happening:


// Default Filter - mimics regular path

( with-config-group default_filter

( string description "default filter" )

( with-config-group buffers
( with-config-group buffer_A
( string-vec size "100%" )
( string type "color" )
( string color_format "RGBA8" )
( bool shared false ) // shared between filters
)
( with-config-group buffer_B
( string-vec size "100%" )
( string type "color" )
( string color_format "RGBA8" )
( string depth_format "NULL" )
( bool shared false ) // shared between filters
)
)

( with-config-group phases

( with-config-group phase1
( string description "Render Pristine Scene with Depth" )
( bool active true )

( with-config-group steps
( with-config-group step1
( string description "Set Render Target" )
( string type "SetRenderTarget" )
( string-vec targets "buffer_A" "buffer_B" )
)
( with-config-group step2
( string description "Clear Render Target Test" )
( string type "Clear" )
( string-vec targets "color" "depth" )
( float-vec color 0.2 0.2 0.2 1 )
( float depth 1.0 )
( int stencil 0 )
)
( with-config-group step3
( string description "Draw Scene!" )
( string type "DrawScene" )
)
)
) // phase 1

( with-config-group phase2
( string description "Draw Quad" )
( bool active true )

( with-config-group steps

( with-config-group step1
( string description "Set Render Target Back" )
( string type "SetRenderTarget" )
( string-vec targets "FrameBufferOut" )
)
( with-config-group step2
( string type "Clear" )
( string-vec targets "color" "depth" )
( float-vec color 0 0 1 1 )
( float depth 1.0 )
( int stencil 0 )
)
( with-config-group step3
( string description "Draw Full Screen Quad" )
( string type "DrawQuad" )
( string texture "buffer_A" )
)
)
) // phase 2

)
)






[Edited by - WOsborn on August 8, 2007 7:08:40 AM]

Share this post


Link to post
Share on other sites
remigius    1172
I think I see what the problem might be. Before rendering the quad in phase 2, you should disable your 2nd render target (with index 1). I'm not sure how this works in native DX, but with MDX it's just a matter of setting it to null, ie:


H = DX9_DEV->SetRenderTarget( 0, screen_OUT );
H = DX9_DEV->SetRenderTarget( 1, NULL );


As it is now, the 2nd target gets overwritten by your quad rendering pass, which probably isn't outputting anything to COLOR1, so it gets cleared and then remains empty.

Share this post


Link to post
Share on other sites
WOsborn    137
Im sorry. I should have added that into my post.
My code does actually go thru and sets them to NULL before
each SetRenderTarget Step. I found that error by running in debug mode.



Phase 1:
// Reset MRT slots
for (unsigned int i = 1; i < DX9_REND->dx9_caps.NumSimultaneousRTs; iplusplus)
{
H = DX9_DEV->SetRenderTarget( i, NULL );
}

H = DX9_DEV->SetRenderTarget( 0, _surf_RENDA );
H = DX9_DEV->SetDepthStencilSurface( _surf_RENDA_depth_surface );
H = DX9_DEV->SetRenderTarget( 1, _surf_RENDB );
-----
H = DX9_DEV->Clear( 0,
NULL,
Color | Depth,
D3DCOLOR_COLORVALUE( 0,0,0, 1 ),
1,
0 );
-----
Render();

Phase 2:
// Reset MRT slots
for (unsigned int i = 1; i < DX9_REND->dx9_caps.NumSimultaneousRTs; iplusplus)
{
H = DX9_DEV->SetRenderTarget( i, NULL );
}

H = DX9_DEV->SetRenderTarget( 0, screen_OUT );
H = DX9_DEV->SetDepthStencilSurface( _screen_depth_surface );
-----
H = DX9_DEV->Clear( 0,
NULL,
Color | Depth,
D3DCOLOR_COLORVALUE( 0,0,0, 1 ),
1,
0 );
-----
Draw_Quad_Using_BufferA();






Any other suggestions? Do I maually have to link up COLOR1 other than
setting the SetRenderTarget(1, surface); call?

[Edited by - WOsborn on August 8, 2007 7:54:09 AM]

Share this post


Link to post
Share on other sites
WOsborn    137
So I ran it in REF (software) mode and it works as programmed.
What would be a reason it would not be working in HAL (hardware) mode?
When run in HW mode and all debugging info is turned on I don't get any errors?

Also:
When running the Pixel Motion Blur demo in NVPerfHUD I can see info being written to the second RT (with a little .fx modification), so Im probably missing some little switch or flag.

(displaying the images is just using a simple shader on a quad with a Tex.x < 0.5 if statement to decide which rt texture to sample from.)

Software Mode:
RT1_______________________RT2
PerfHud Image 5

Hardware Mode:
RT1_______________________RT2
PerfHud Image 6

[Edited by - WOsborn on August 5, 2007 3:04:10 PM]

Share this post


Link to post
Share on other sites
remigius    1172
I'm out of good suggestions, but if it works with the REF device it might be worth considering to try this on some different hardware to see if the problem goes away. If so, there might be something off with your current hardware or drivers. You also might want to make sure the debug runtimes are set to output as much info as possible (dragging the sliders all the way to the right) and that the max validation option is checked. If this doesn't produce any errors or relevant warnings, it's more likely that it's a hardware error and it's probably your best bet to take this to the NVidia developer support forums.

One final thing I'd try would be to output the textures to a file right after the MRT 'setup pass', so before you do anything else, ie. Phase 2. If the textures come out right at this point, you'll know something's going wrong with the subsequent code. If they don't come out ok, then there's really something fishy going on with the MRTs.

Share this post


Link to post
Share on other sites
WOsborn    137
Well it looks like I found the problem.

I guess you can't setup your renderTargets and then render an object that has a pixel shader that returns only a COLOR0 ( a non-MRT object )

float4 pixelShader : COLOR0
{
return float4(0,0,1,1);
}


and then render an object that returns a struct used for MRT right after it.

struct colorRet
{
float4 C0 : COLOR0;
float4 C1 : COLOR1;
};
colorRet pixelShaderMRT
{
colorRet OUT;
OUT.C0 = float4(0,0,1,1);
OUT.C1 = float4(1,0,0,1);
return OUT;
}


If I render the non MRT object second it works fine. (haven't tried continuing the cycle)

Has anyone seen this? Are there any workarounds for this? Do you have to sort objects according to this? Can you not have 3 RTs set the whole time you're rendering your objects, and only a certain number of objects write to certain RTs and then composite at the end??

-WOsborn

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this