Skip to main content
gamedev.net
🔒 Locked

MRT problems

Started by mjshorty Feb 27, 2008 at 10:44 AM 5 replies 1.8k views
Original Post
mjshorty
mjshorty
Hi, im creating a Deferred shading engine in DX9 and Im having a problem with my 4th render target. Im using the first for position, second for normals, third for diffuse and 4th for specular, with the .a components used for various other things. Anyway if i use 3 render targets, everything works fine, but when I set the 4th RT (specular) I get the an error saying: Direct3D9: (WARN) :Can not render to a render target that is also used as a texture. A render target was detected as bound, but couldn't detect if texture was actually used in rendering. This error only occurs when I try to render a mesh to the MRT's. If I set the target, then un-set it, then pass the texture through to the uber shader evrything is fine. When using 4 render targets the frame rate slowls creeps downward, leading me to think there is a memory leak somewhere? Any ideas? I call ConstructGBuffer() first, then render my scene, then call FinalizeGBuffer(), followed by ConstructLightBuffers(), after that I send my light render targets to another post processing effect to do other stuff with. Header:

#ifndef S3DDEFERREDSHADINGD3D9_H
#define S3DDEFERREDSHADINGD3D9_H

#include <d3d9.h>
#include <d3dx9.h>

#include "S3DEffectD3D9.h"

class S3DDeferredShadingD3D9
{
	private:
		// G-Buffer
		IDirect3DTexture9* RT0;	// (pos.x,  pos.y,  pos.z, material ID)
		IDirect3DTexture9* RT1;	// (norm.x, norm.y, norm.z, null)
		IDirect3DTexture9* RT2;	// (diff.r, diff.g, diff.b, spec intensity)
		IDirect3DTexture9* RT3;	// (spec.r, spec.g, spec.b, spec power)

		IDirect3DTexture9* RTDiff;	// render target to store diffuse lighting terms
		IDirect3DTexture9* RTSpec;	// render target to store specular lighting terms

		IDirect3DSurface9* pBackBuffer;	// back buffer

		S3DEffectD3D9	fxLighting;	// lghting effect

		// effect handles
		D3DXHANDLE h_vecLightDir;
		D3DXHANDLE h_vecView;

		D3DXHANDLE h_RT0;
		D3DXHANDLE h_RT1;
		D3DXHANDLE h_RT2;
		D3DXHANDLE h_RT3;

		void SetRenderTarget(LPDIRECT3DDEVICE9 pDevice, UINT iNum,IDirect3DTexture9* pTex);	// set render target

		// screen aligned quad vertex structure
		struct QuadVertex
		{
			D3DXVECTOR4 pos;
		};
		
		// screen aligned quad
		QuadVertex quad[4];

		IDirect3DVertexDeclaration9*	pVertDeclPos;			// pos

	public:
		S3DDeferredShadingD3D9();	// constructor
		~S3DDeferredShadingD3D9();	// destructor

		bool Initialise(LPDIRECT3DDEVICE9 pDevice, UINT iWidth, UINT iHeight);	// initialise
		
		void ConstructGBuffer(LPDIRECT3DDEVICE9 pDevice);	// fill G-Buffer with material data
		void FinaliseGBuffer(LPDIRECT3DDEVICE9 pDevice);	// finalise G-Buffer construction

		void ConstructLightBuffers(LPDIRECT3DDEVICE9 pDevice, D3DXVECTOR3 vView);	// fill the light buffers with data

		IDirect3DTexture9* GetDiffuseTexture();	// returns the diffuse texture
		IDirect3DTexture9* GetSpecularTexture();// returns the specular texture
};

#endif

Source:

#include "S3DDeferredShadingD3D9.h"

// constructor
S3DDeferredShadingD3D9::S3DDeferredShadingD3D9()
{
	RT0 = NULL;
	RT1 = NULL;
	RT2 = NULL;
	RT3 = NULL;

	RTDiff = NULL;
	RTSpec = NULL;

	pBackBuffer = NULL;

	h_vecLightDir = NULL;
	h_vecView =NULL;
	h_RT0 = NULL;
	h_RT1 = NULL;
	h_RT2 = NULL;
	h_RT3 = NULL;

	pVertDeclPos = NULL;
}

// destructor
S3DDeferredShadingD3D9::~S3DDeferredShadingD3D9()
{
	// release render targets
	if(RT0 != NULL)
		RT0->Release();

	if(RT1 != NULL)
		RT1->Release();

	if(RT2 != NULL)
		RT2->Release();

	if(RT3 != NULL)
		RT3->Release();

	if(RTDiff != NULL)
		RTDiff->Release();

	if(RTSpec != NULL)
		RTSpec->Release();

	if(pBackBuffer != NULL)
		pBackBuffer->Release();
	
	if(pVertDeclPos != NULL)
		pVertDeclPos->Release();
}

// initialise
bool S3DDeferredShadingD3D9::Initialise(LPDIRECT3DDEVICE9 pDevice, UINT iWidth, UINT iHeight)
{
	HRESULT hr;
	D3DFORMAT Format = D3DFMT_A16B16G16R16F;
	DWORD Usage = D3DUSAGE_RENDERTARGET;
	D3DPOOL Pool = D3DPOOL_DEFAULT;

	// create G-Buffer render targets
	hr = pDevice->CreateTexture(iWidth, iHeight, 0, Usage, Format, Pool, &RT0, NULL);
	if(FAILED(hr))
		return false;

	hr = pDevice->CreateTexture(iWidth, iHeight, 0, Usage, Format, Pool, &RT1, NULL);
	if(FAILED(hr))
		return false;
	
	hr = pDevice->CreateTexture(iWidth, iHeight, 0, Usage, Format, Pool, &RT2, NULL);
	if(FAILED(hr))
		return false;

	hr = pDevice->CreateTexture(iWidth, iHeight, 0, Usage, Format, Pool, &RT3, NULL);
	if(FAILED(hr))
		return false;

	// create lighting render targets
	hr = pDevice->CreateTexture(iWidth, iHeight, 0, Usage, Format, Pool, &RTDiff, NULL);
	if(FAILED(hr))
		return false;

	hr = pDevice->CreateTexture(iWidth, iHeight, 0, Usage, Format, Pool, &RTSpec, NULL);
	if(FAILED(hr))
		return false;

	// load lighting shader
	fxLighting.LoadShader(pDevice, TEXT("Content/FX/DL_Effects.fx"), TEXT("DeferredShading"));

	// pos vertex decleration
	D3DVERTEXELEMENT9 declVertexP[] = 
	{
		{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
		D3DDECL_END()
	};

	// create decleration
	hr = pDevice->CreateVertexDeclaration(declVertexP, &pVertDeclPos);
	if(FAILED(hr))
		return false;

	// get effect paramaters
	h_vecLightDir	= fxLighting.GetShader()->GetParameterByName(NULL, "vecLightDir");
	h_vecView		= fxLighting.GetShader()->GetParameterByName(NULL, "vecView");

	h_RT0 = fxLighting.GetShader()->GetParameterByName(NULL, "RT0");	
	h_RT1 = fxLighting.GetShader()->GetParameterByName(NULL, "RT1");
	h_RT2 = fxLighting.GetShader()->GetParameterByName(NULL, "RT2");
	h_RT3 = fxLighting.GetShader()->GetParameterByName(NULL, "RT3");
	
	// screen aligned quad
	float w = iWidth / 2.0f;
	float h = iHeight / 2.0f;

	quad[0].pos = D3DXVECTOR4( -w, -h, 0.0f, 1.0f );
    quad[1].pos = D3DXVECTOR4( w, -h, 0.0f, 1.0f );
    quad[2].pos = D3DXVECTOR4( -w, h, 0.0f, 1.0f );
    quad[3].pos = D3DXVECTOR4( w, h, 0.0f, 1.0f );

	return true;
}

// set render target
void S3DDeferredShadingD3D9::SetRenderTarget(LPDIRECT3DDEVICE9 pDevice, UINT iNum, IDirect3DTexture9* pTex)
{
	// create new surface
	IDirect3DSurface9* pRenderSurface = NULL;

	// get surface from render target
	pTex->GetSurfaceLevel(0, &pRenderSurface);

	// set the render target
	pDevice->SetRenderTarget(iNum, pRenderSurface);
	
	// release surface
	pRenderSurface->Release();
}

// construct the G-Buffer
void S3DDeferredShadingD3D9::ConstructGBuffer(LPDIRECT3DDEVICE9 pDevice)
{
	// get back buffer
    pDevice->GetRenderTarget(0, &pBackBuffer);

	// set multiple render targets
	SetRenderTarget(pDevice, 0, RT0);
	SetRenderTarget(pDevice, 1, RT1);
	SetRenderTarget(pDevice, 2, RT2);
	SetRenderTarget(pDevice, 3, RT3);

	// clear rt
	pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(0, 0, 0, 0), 1.0f, 0);
}

// finalise the G-Buffer
void S3DDeferredShadingD3D9::FinaliseGBuffer(LPDIRECT3DDEVICE9 pDevice)
{
	// reset render targets
	pDevice->SetRenderTarget(0, pBackBuffer);
	pDevice->SetRenderTarget(1, NULL);
	pDevice->SetRenderTarget(2, NULL);
	pDevice->SetRenderTarget(3, NULL);

	// release back buffer
	if(pBackBuffer != NULL)
	{
		pBackBuffer->Release();
		pBackBuffer = NULL;
	}
}	

void S3DDeferredShadingD3D9::ConstructLightBuffers(LPDIRECT3DDEVICE9 pDevice, D3DXVECTOR3 vView)
{
	// set shader paramaters
	fxLighting.GetShader()->SetVector(h_vecLightDir, &D3DXVECTOR4(-1.0f, 1.0f, -1.0f, 0.0f));	
	fxLighting.GetShader()->SetVector(h_vecView, &D3DXVECTOR4(vView, 1.0f));
	
	fxLighting.GetShader()->SetTexture(h_RT0, RT0);
	fxLighting.GetShader()->SetTexture(h_RT1, RT1);
	fxLighting.GetShader()->SetTexture(h_RT2, RT2);
	fxLighting.GetShader()->SetTexture(h_RT3, RT3);

	// set render states
	pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
	pDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);

	// get back buffer
    pDevice->GetRenderTarget(0, &pBackBuffer);

	//// set multiple render targets
	SetRenderTarget(pDevice, 0, RTDiff);
	SetRenderTarget(pDevice, 1, RTSpec);

	// set vertex decl
	pDevice->SetVertexDeclaration(pVertDeclPos);

	// set technique
	fxLighting.GetShader()->SetTechnique("DL_BuildLighting");

	UINT cPasses = 1;
	fxLighting.GetShader()->Begin(&cPasses, D3DXFX_DONOTSAVESTATE);
	
	// for each pass in the technique
	for(UINT iPass = 0; iPass < cPasses; iPass++)
	{
		fxLighting.GetShader()->BeginPass(iPass);

		// apply changes
		fxLighting.GetShader()->CommitChanges();

		// render screen aligned quad
		pDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(QuadVertex));

		// end pass
		fxLighting.GetShader()->EndPass();
	}

	// end effect
	fxLighting.GetShader()->End();

	//reset render targets
	pDevice->SetRenderTarget(0, pBackBuffer);
	pDevice->SetRenderTarget(1, NULL);

	// release back buffer
	if(pBackBuffer != NULL)
	{
		pBackBuffer->Release();
		pBackBuffer = NULL;
	}

	// reset render states
	pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
	pDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
}

IDirect3DTexture9* S3DDeferredShadingD3D9::GetDiffuseTexture()
{
	if(RTDiff != NULL)
	{
		return RTDiff;
	}

	return NULL;
}

IDirect3DTexture9* S3DDeferredShadingD3D9::GetSpecularTexture()
{
	if(RTSpec != NULL)
	{
		return RTSpec;
	}

	return NULL;
}

MJP
MJP
I'd guess you're probably leaving your 4th G-Buffer texture bound to the device after your lighting pass. Make sure you set the sampler (or texture parameter if you're using effects) to NULL after you're done with it.

Also I don't know if you're interested or not, but there's been various discussions in Graphics Programming and Theory about ways to pack your G-Buffer in order to reduce the amount of render-targets and the bpp required for each. In particular storing linear eye-space depth and then using that to reconstruct world-space or view-space position is particular, as is storing normals as spherical coordinates.
mjshorty
mjshorty
yea been reading about it, Im just going with the fp reder targets at the min tho, from what ive read its 50/50 after all the unpacking and what not has been calculated.

I've set all the render targets to NULL (bar the 1st, just reset that back to the back buffer) which is why I dont understand why its returning that error.
jollyjeffers
jollyjeffers
Quote:
Original post by mjshort
I've set all the render targets to NULL (bar the 1st, just reset that back to the back buffer) which is why I dont understand why its returning that error.
PIX is your friend here.

Use D3DPERF_SetMarker() and friends to annotate your command stream and then identify the draw call that's causing you problems. Look at the device state for this call and you'll probably find that your texture is bound to a sampler as per the error message.

Scan backwards through the command stream and see where that sampler was bound. Chances are that you've got a logic bug in your code so you think you're resetting it to NULL but you're not actually...

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ |
mjshorty
mjshorty
Hi, never used Pix before, been playing round with it, its an amzing tool, anyway. After going though my code, to make sure no textures are bound, after setting a texture and calling draw, i then call SetTexture(pTex, NULL). which means that no textures should be bound. Yet when I look in Pix there are still textures bound to a sampler at the beginning of the frame. Is this normal? Is there a way to unbind the texture from the sample other thatn what ive been doing?
jollyjeffers
jollyjeffers
No, thats the only way of resetting a texture sampler. However, if you're using things like the Effects Framework it could be (re-)setting pipeline state without you explicitly saying so.

Looking up in PIX where these events occur should identify who/what is changing pipeline state, at which point you can decide if and how your code should be changed...

hth
Jack
<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ |
mjshorty
mjshorty
Ive gone through the events in pix and cant identify where there would be a proble.
I have noticed something though, whe in Visual Studio, if i compile and run m project, the warning appears in the output, and the frame rate drops. However if i run the project straight form the .exe the frame rate stays constant, obviousily there is no output though. If i run it in peftHuf too the frame rate is constant. Could this be a problem with Visual Studio/DirectX perhaps?

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.