Multiple Render Targets - MRT Support [DX9]

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Multiple Render Targets - MRT Support [DX9]

Post by Nadro »

Hi. I done Multiple Render Targets support for Irrlicht [Now for DirectX9 only, but I'm working on it for OpenGL]

You have to update this Irrlicht parts for usage MRT:

Code: Select all

		             *** Irrlicht Include ***

------------------------------------- IVideoDriver.h -------------------------------------
virtual bool setRenderTarget(core::array<video::ITexture*> texture, bool clearBackBuffer=true, bool clearZBuffer=true, SColor color=video::SColor(0,0,0,0)) = 0;
------------------------------------------------------------------------------------------
********************************************************************

		             *** Irrlicht Source ***

------------------------------------- CNullDriver.h -------------------------------------
virtual bool setRenderTarget(core::array<video::ITexture*> texture, bool clearBackBuffer, bool clearZBuffer, SColor color);
------------------------------------------------------------------------------------------
********************************************************************

------------------------------------ CNullDriver.cpp ------------------------------------
bool CNullDriver::setRenderTarget(core::array<video::ITexture*> texture, bool clearBackBuffer, bool clearZBuffer, SColor color)
{
	return false;
}
------------------------------------------------------------------------------------------
********************************************************************

------------------------------------ CD3D9Driver.h ------------------------------------
virtual bool setRenderTarget(core::array<video::ITexture*> texture, bool clearBackBuffer=false, bool clearZBuffer=false, SColor color=video::SColor(0,0,0,0));
------------------------------------------------------------------------------------------
********************************************************************

----------------------------------- CD3D9Driver.cpp -----------------------------------
bool CD3D9Driver::setRenderTarget(core::array<video::ITexture*> texture,
			bool clearBackBuffer, bool clearZBuffer,
			SColor color)
{
	// check for right driver type

	for(int i = 0; i < texture.size(); i++)
	{
		if (texture[i] && texture[i]->getDriverType() != EDT_DIRECT3D9)
		{
			os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR);
			return false;
		}

		// check for valid render target

		CD3D9Texture* tex = (CD3D9Texture*)texture[i];

		if (texture[i] && !tex->isRenderTarget())
		{
			os::Printer::log("Fatal Error: Tried to set a non render target texture as render target.", ELL_ERROR);
			return false;
		}

		if (texture[i] && (tex->getSize().Width > ScreenSize.Width ||
			tex->getSize().Height > ScreenSize.Height ))
		{
			os::Printer::log("Error: Tried to set a render target texture which is bigger than the screen.", ELL_ERROR);
			return false;
		}
	}

	// check if we should set the previous RT back

	bool ret = true;

	// check only first texture from array
	if (texture[0] == 0)
	{
		if (PrevRenderTarget)
		{
			if (FAILED(pID3DDevice->SetRenderTarget(0, PrevRenderTarget)))
			{
				os::Printer::log("Error: Could not set back to previous render target.", ELL_ERROR);
				ret = false;
			}

			CurrentRendertargetSize = core::dimension2d<s32>(0,0);
			PrevRenderTarget->Release();
			PrevRenderTarget = 0;

			for(int i = 1; i < texture.size(); i++)
			{
				pID3DDevice->SetRenderTarget(i, NULL);
			}
			
		}
	}
	else
	{
		// we want to set a new target. so do this.

		// store previous target

		if (!PrevRenderTarget)
		if (FAILED(pID3DDevice->GetRenderTarget(0, &PrevRenderTarget)))
		{
			os::Printer::log("Could not get previous render target.", ELL_ERROR);
			return false;
		}

		// set new render target
		for(int i = 0; i < texture.size(); i++)
		{
			// set current texture
			CD3D9Texture* tex = (CD3D9Texture*)texture[i];

			if (FAILED(pID3DDevice->SetRenderTarget(i, tex->getRenderTargetSurface())))
			{
				os::Printer::log("Error: Could not set render target.", ELL_ERROR);
				return false;
			}

			CurrentRendertargetSize = tex->getSize();
		}
	}

	if (clearBackBuffer || clearZBuffer)
	{
		DWORD flags = 0;

		if (clearBackBuffer)
			flags |= D3DCLEAR_TARGET;

		if (clearZBuffer)
			flags |= D3DCLEAR_ZBUFFER;

		pID3DDevice->Clear(0, NULL, flags, color.color, 1.0f, 0);
	}

	return ret;
}
------------------------------------------------------------------------------------------
********************************************************************
You have to update setRenderTarget function for all Your drivers eg. Software Driver, OpenGL and replace texture as texture[0] in this functions.

Simple usage:

Code: Select all

// You have to create RTT textures with good resolutions (no diffrence!)
ITexture* RTT1 = Driver->createRenderTargetTexture(dimension2d<s32>(512,512));
ITexture* RTT2 = Driver->createRenderTargetTexture(dimension2d<s32>(512,512));

// You have to create Array with this textures usage in MRT
array<ITexture*> arrTex;

// You have put textures to this array
arrTex.push_back(RTT1);
arrTex.push_back(RTT2);

// Now You setRenderTarget with textures array:
Driver->setRenderTarget(arrTex, true, true, SColor(255,0,0,0));

// Draw Yours data and write per shaders infos to Yours Textures

// You have to disable Render Target, so You have to change first component of array to 'NULL'
arrTex[0] = 0;
// Now array with 'NULL' value disable Render Target
Driver->setRenderTarget(arrTex);
// You have to set good value for first array component
arrTex[0] = RTT1;

// It's all! You have MRT support in Yours application!
This is code for Irrlicht 1.4 but it's easy to implementation for SVN revision. Maybe Irrlicht Team can merge it with Irrlicht core on SVN, when I add OpenGL support? MRT is very useful for creating shaders eg. Motion Blur.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Post by Nadro »

Maybe better idea is no change standard function:

Code: Select all

bool setRenderTarget(video::ITexture* texture, bool clearBackBuffer, bool clearZBuffer, SColor color);
but add new:

Code: Select all

bool setMultipleRenderTarget(core::array<video::ITexture*> texture, bool clearBackBuffer, bool clearZBuffer, SColor color);
or You have use overload c++ to function setRenderTarget. I think than add new setMultipleRenderTarget function or overloaded setRnderTarget is the best idea:) because usage array in standard One Render Target operations is not comfortable:)
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Yes, overloading is better. However, I'd prefer a version where I could access the internal texture array, i.e. push_back methods to avoid the additional array structure.
However, the resetting of the MRTs seems to be wrong in your method. If I change from MRT to the main buffer I have to pass an array of empty textures, otherwise most render targets are not released.
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Post by Nadro »

Resetting MRT is good. I tested it and all it's ok :)

Test looks like this:
* I write to 3 textures via MRT and I put textures on 3 nodes
* Next I render scene to one texture (without MRT) using standard Irrlicht RTT function and put this texture on fourth node
All looks properly :)
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Yes, sure, visually correct. But you don't release them. Check the version for one RTT and count the releases done there, compare it with those made if you change from one array to another (possibly null textures array). You'll have to store the number of active RTTs and release them properly in each method.
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Post by Nadro »

You needn't release all surfeces only 1 - first:

Code: Select all

pID3DDevice->SetRenderTarget(0, PrevRenderTarget)
other You should disable, so:

Code: Select all

for(int i = 1; i < texture.size(); i++)
{
// First texture can't be NULL, so int i = 1
pID3DDevice->SetRenderTarget(i, NULL);
}
All it's fine:)
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

Wow, thanks.
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Post by Nadro »

If You need integrated MRTs with Floating Point Textures and support this in OpenGL and DirectX9 You should go to this topic:
http://irrlicht.sourceforge.net/phpBB2/ ... hp?t=25496
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
Post Reply