Original Post
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: Source:
#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
#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;
}