[DirectX] RenderTarget XXL (larger than screen size)

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
vi-wer
Posts: 93
Joined: Sun May 20, 2007 7:15 pm
Location: Germany
Contact:

[DirectX] RenderTarget XXL (larger than screen size)

Post by vi-wer »

As you maybe know it's not possible to create a rendertarget larger than the screen when using Direct3D9 driver, even though it seems to work fine with OpenGL.
The reason for this is the ZBuffer: one ZBuffer is used for all rendertargets.
The solution? Every rendertarget needs its own ZBuffer.

Four files have to be modified for this:
- CD3D9Texture.h
- CD3D9Texture.cpp
- CD3D9Driver.h
- CD3D9Driver.cpp


These files are located in irrlichts source directory. I modified Irrlicht-1.4-beta but older versions are the same I guess.

And here's the code. Just add/replace the code from the files with the following (new/important lines are marked with a comment):

CD3D9Texture.h:

Code: Select all

   // .....
	//! returns if it is a render target
	virtual bool isRenderTarget() const;

	//! Returns pointer to the render target surface
	IDirect3DSurface9* getRenderTargetSurface();
	
	//! Returns pointer to the render target ZBuffer surface	
	IDirect3DSurface9* getRenderZBufferTargetSurface();		// <= this is new

private:

	void createRenderTarget();
	// ....

Code: Select all

    // ....
	
	IImage* Image;
	IDirect3DDevice9* Device;
	IDirect3DTexture9* Texture;
	IDirect3DTexture9* ZStencilBuffer;	// <= this is new
	IDirect3DSurface9* RTTSurface;
	// ....
CD3D9Texture.cpp:

Code: Select all

// ....

CD3D9Texture::CD3D9Texture(CD3D9Driver* driver, core::dimension2d<s32> size, const char* name)
: ITexture(name), Image(0), Texture(0), RTTSurface(0), Driver(driver),ZStencilBuffer(0),	// <= set ZStencilBuffer to zero in both constructors
	TextureSize(size), ImageSize(size), Pitch(0),
	HasMipMaps(false), HardwareMipMaps(false), IsRenderTarget(true)
	
// ........

CD3D9Texture::CD3D9Texture(IImage* image, CD3D9Driver* driver,
					   u32 flags, const char* name)
: ITexture(name), Image(image), Texture(0), RTTSurface(0), Driver(driver),ZStencilBuffer(0),	// <= here too
TextureSize(0,0), ImageSize(0,0), Pitch(0),
HasMipMaps(false), HardwareMipMaps(false), IsRenderTarget(false)

// .............

Code: Select all

// .............

void CD3D9Texture::createRenderTarget()	// replace the original function with this one
{
	TextureSize.Width = getTextureSizeFromImageSize(TextureSize.Width);
	TextureSize.Height = getTextureSizeFromImageSize(TextureSize.Height);

	// get backbuffer format to create the render target in the
	// same format

	IDirect3DSurface9* bb;
	D3DFORMAT d3DFormat = D3DFMT_A8R8G8B8;

	if (!FAILED(Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &bb)))
	{
		D3DSURFACE_DESC desc;
		bb->GetDesc(&desc);
		d3DFormat = desc.Format;

		if (d3DFormat == D3DFMT_X8R8G8B8)
			d3DFormat = D3DFMT_A8R8G8B8;

		bb->Release();
	}
	else
	{
		os::Printer::log("Could not create RenderTarget texture: could not get BackBuffer.",
			ELL_WARNING);
		return;
	}

	// create texture
	HRESULT hr;

	// create texture
	hr = Device->CreateTexture(
		TextureSize.Width,
		TextureSize.Height,
		1, // mip map level count, we don't want mipmaps here
		D3DUSAGE_RENDERTARGET,
		d3DFormat,
		D3DPOOL_DEFAULT,
		&Texture,
		NULL);

	if (FAILED(hr))
		os::Printer::log("Could not create render target texture");

	// create ZStencilBuffer				<= this one's new
	hr = Device->CreateTexture(
		TextureSize.Width,
		TextureSize.Height,
		1, // mip map level count, we don't want mipmaps here
		D3DUSAGE_DEPTHSTENCIL,
		D3DFMT_D16,	// or D3DFMT_D32, D3DFMT_D24S8 (8Bit stencil) , D3DFMT_D24X8 (32Bit , 8Bit unused) - see DX9 doc for other formats
		D3DPOOL_DEFAULT,
		&ZStencilBuffer,
		NULL);

	// get irrlicht format from D3D format
	ColorFormat = getColorFormatFromD3DFormat(d3DFormat);

	if (FAILED(hr))
		os::Printer::log("Could not create render target ZBuffer");
}

// ..............

Code: Select all

// ..............

//! Returns pointer to the render target ZBuffer surface
IDirect3DSurface9* CD3D9Texture::getRenderZBufferTargetSurface()	// <= add this function after "IDirect3DSurface9* CD3D9Texture::getRenderTargetSurface()"
{
	if (!IsRenderTarget)
		return 0;

	IDirect3DSurface9 *pRTTSurface = 0;
	if (ZStencilBuffer)
		ZStencilBuffer->GetSurfaceLevel(0, &pRTTSurface);

	if (pRTTSurface)
		pRTTSurface->Release();

	return pRTTSurface;
}
// ...............
CD3D9Driver.h:

Code: Select all

// .........

	IDirect3DSurface9* PrevRenderTarget;		// <= this is old ^-^ (leave it)
	IDirect3DSurface9* PrevZStencilBuffer;		// <= this is new
	core::dimension2d<s32> CurrentRendertargetSize;
	
	// ....
CD3D9Driver.cpp:

Code: Select all

// .....

//! constructor
CD3D9Driver::CD3D9Driver(const core::dimension2d<s32>& screenSize, HWND window,
				bool fullscreen, bool stencilbuffer,
				io::IFileSystem* io, bool pureSoftware)
: CNullDriver(io, screenSize), CurrentRenderMode(ERM_NONE),
	ResetRenderStates(true), Transformation3DChanged(false), StencilBuffer(stencilbuffer),
	D3DLibrary(0), pID3D(0), pID3DDevice(0), PrevRenderTarget(0),PrevZStencilBuffer(0),	// <= set ZBuffer to zero
	LastVertexType((video::E_VERTEX_TYPE)-1), MaxTextureUnits(0), MaxUserClipPlanes(0),
	MaxLightDistance(sqrtf(FLT_MAX)), LastSetLight(-1), DeviceLost(false),
	Fullscreen(fullscreen)
	
// ....

Code: Select all

// ....

//! sets a render target
bool CD3D9Driver::setRenderTarget(video::ITexture* texture,		// <= replace original function with this one
			bool clearBackBuffer, bool clearZBuffer,
			SColor color)
{
	// check for right driver type

	if (texture && texture->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;

	if (texture && !tex->isRenderTarget())
	{
		os::Printer::log("Fatal Error: Tried to set a non render target texture as render target.", ELL_ERROR);
		return false;
	}
		
	// next code is useless now
/*
	if (texture && (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;

	if (tex == 0)
	{
		if (PrevRenderTarget)
		{
			// Set default render target
			if (FAILED(pID3DDevice->SetRenderTarget(0, PrevRenderTarget)))
			{
				os::Printer::log("Error: Could not set back to previous render target.", ELL_ERROR);
				ret = false;
			}

			// Set default ZStencilBuffer target
			if (FAILED(pID3DDevice->SetDepthStencilSurface(PrevZStencilBuffer)))		// <= this is new
			{
				os::Printer::log("Error: Could not set back to previous render target ZBuffer.", ELL_ERROR);
				ret = false;
			}

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

			PrevZStencilBuffer->Release();		// <= this is new too
			PrevZStencilBuffer = 0;
		}
	}
	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;
			}

			if (FAILED(pID3DDevice->GetDepthStencilSurface( &PrevZStencilBuffer)))  // <= guess what that is
			{
				os::Printer::log("Could not get previous render target ZBuffer.", ELL_ERROR);
				return false;
			}
		}


		// set new render target

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

		if (FAILED(pID3DDevice->SetDepthStencilSurface( tex->getRenderZBufferTargetSurface()))) // <= add this?
		{
			os::Printer::log("Error: Could not set render target ZBuffer.", 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;
}

// ..........
The only thing left is to compile the engine. As long I haven't forgot anything you shouldn't get any errors (concerning the textures).
Now it should be possible to use 2048x2048 rendertargets with a screen resolution of 320x240. 8)
Enjoy it.
Last edited by vi-wer on Tue May 06, 2008 6:41 pm, edited 1 time in total.
alexionne
Posts: 55
Joined: Fri Jun 22, 2007 9:55 am
Location: Novi Sad, Serbia

Re: [DirectX] RenderTarget XXL (larger than screen res)

Post by alexionne »

vi-wer wrote:As you maybe know it's not possible to create a rendertarget larger than the screen when using Direct3D9 driver, even though it seems to work fine with OpenGL.
The reason for this is the ZBuffer: one ZBuffer is used for all rendertargets.
The solution? Every rendertarget needs its own ZBuffer.
There is another solution: that you have one ZBuffer which size is equal to size of largest render target. That way, you don't need to chage ZBuffer, but you can reuse that one.

It could be implement in two ways: 1. you have to set that size manually; 2. automatic "resize" of ZBuffer, ie. automatic destruction and recreation of ZBuffer
sio2
Competition winner
Posts: 1003
Joined: Thu Sep 21, 2006 5:33 pm
Location: UK

Re: [DirectX] RenderTarget XXL (larger than screen res)

Post by sio2 »

vi-wer wrote: The solution? Every rendertarget needs its own ZBuffer.
A shareable depth-buffer makes more sense. I read something about this on the DirectX mailing list a few days ago. At a certain driver-defined point, such as when the driver runs out of HiZ space on the chip, subsequent depth-buffers will be of significantly lower performance. I think it was after about the 4th buffer (driver dependant).
vi-wer
Posts: 93
Joined: Sun May 20, 2007 7:15 pm
Location: Germany
Contact:

Post by vi-wer »

You're right. I thought about using a shared ZBuffer after I posted the code here, too. I'll imropve the code and post it again.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Since you're probably working with SVN it would make sense to provide patch files - Just upload them to the patch tracker on the SF project page of Irrlicht.
vi-wer
Posts: 93
Joined: Sun May 20, 2007 7:15 pm
Location: Germany
Contact:

Post by vi-wer »

Alright, here's the new code. Everytime a new rendertarget is created or dropped it will check if the DepthBuffer size is ok or if a new buffer is required. If the last one is the case, it will replace the old DepthBuffer by a new. Any render target size is possible if it's supported. The size of all render targets is stored inside a static array.
I also discovered that the render target size is limited to 4096x4096 and to a certain number of possible targets. (It's either my hardware or DirectX)
I made some tests: I created a render target with a size of 4096x4096 and dropped it immediately ten times in a for loop. Everytime the depth buffer was resized without errors or warnings. But when I tried to create 4 targets of the same size (without dropping the previous) a got an 'out of memory'-error (texture only not depth buffer). I guess that proves that the code is working fine 8) .
Well here's the content of the patch file. I applied the changes to the latest SVN revision of the files.

Code: Select all

Index: source/Irrlicht/CD3D9Driver.h
===================================================================
--- source/Irrlicht/CD3D9Driver.h	(revision 969)
+++ source/Irrlicht/CD3D9Driver.h	(working copy)
@@ -91,6 +91,9 @@ namespace video
 				u32 bits, bool fullScreen, bool pureSoftware,
 				bool highPrecisionFPU, bool vsync, bool antiAlias);
 
+        //! sets a new depth buffer
+        bool setDepthBuffer(IDirect3DSurface9 *depthbuffer);
+
 		//! \return Returns the name of the video driver. Example: In case of the DIRECT3D8
 		//! driver, it would return "Direct3D8.1".
 		virtual const wchar_t* getName() const;
@@ -190,6 +193,12 @@ namespace video
 		//! \param enable: If true, enable the clipping plane else disable it.
 		virtual void enableClipPlane(u32 index, bool enable);
 
+		//! Helper function, returns Direct3D Caps
+		D3DCAPS9& getCaps()
+		{
+		    return Caps;
+		}
+
 	private:
 
 		// enumeration for rendering modes such as 2d and 3d for minizing the switching of renderStates.
@@ -280,6 +289,7 @@ namespace video
 
 		IDirect3DSurface9* PrevRenderTarget;
 		core::dimension2d<s32> CurrentRendertargetSize;
+		core::dimension2d<s32> CurrentDepthBufferSize;
 
 		D3DCAPS9 Caps;

Index: source/Irrlicht/CD3D9Driver.cpp
===================================================================
--- source/Irrlicht/CD3D9Driver.cpp	(revision 1004)
+++ source/Irrlicht/CD3D9Driver.cpp	(working copy)
@@ -158,6 +158,7 @@ bool CD3D9Driver::initDriver(const core:
 {
 	HRESULT hr;
 	Fullscreen = fullScreen;
+	CurrentDepthBufferSize = screenSize;
 
 	if (!pID3D)
 	{
@@ -537,7 +538,7 @@ bool CD3D9Driver::queryFeature(E_VIDEO_D
 	case EVDF_MIP_MAP:
 		return (Caps.TextureCaps & D3DPTEXTURECAPS_MIPMAP) != 0;
 	case EVDF_MIP_MAP_AUTO_UPDATE:
-		// always return false because a lot of drivers claim they do 
+		// always return false because a lot of drivers claim they do
 		// this but actually don't do this at all.
 		return false; //(Caps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP) != 0;
 	case EVDF_STENCIL_BUFFER:
@@ -692,10 +693,10 @@ bool CD3D9Driver::setRenderTarget(video:
 		return false;
 	}
 
-	if (texture && (tex->getSize().Width > ScreenSize.Width ||
-		tex->getSize().Height > ScreenSize.Height ))
+	if (texture && (tex->getSize().Width > CurrentDepthBufferSize.Width ||
+		tex->getSize().Height > CurrentDepthBufferSize.Height ))
 	{
-		os::Printer::log("Error: Tried to set a render target texture which is bigger than the screen.", ELL_ERROR);
+		os::Printer::log("Error: Tried to set a render target texture which is bigger than the depth buffer.", ELL_ERROR);
 		return false;
 	}
 
@@ -759,12 +760,22 @@ bool CD3D9Driver::setRenderTarget(video:
 }
 
 
+//! sets a new depth buffer
+bool CD3D9Driver::setDepthBuffer(IDirect3DSurface9 *depthbuffer)
+{
+    D3DSURFACE_DESC desc;
+	depthbuffer->GetDesc(&desc);
+
+    CurrentDepthBufferSize = core::dimension2d<s32>( desc.Width,desc.Height );
+    pID3DDevice->SetDepthStencilSurface( depthbuffer );
+}
+
 
 //! sets a viewport
 void CD3D9Driver::setViewPort(const core::rect<s32>& area)
 {
 	core::rect<s32> vp = area;
-	core::rect<s32> rendert(0,0, ScreenSize.Width, ScreenSize.Height);
+	core::rect<s32> rendert(0,0, CurrentDepthBufferSize.Width, CurrentDepthBufferSize.Height);
 	vp.clipAgainst(rendert);
 
 	D3DVIEWPORT9 viewPort;
@@ -890,7 +901,7 @@ void CD3D9Driver::draw2DImage(const vide
 	npos.UpperLeftCorner.X = ( destRect.UpperLeftCorner.X * xFact ) - 1.0f;
 	npos.UpperLeftCorner.Y = 1.0f - ( destRect.UpperLeftCorner.Y * yFact );
 	npos.LowerRightCorner.X = ( destRect.LowerRightCorner.X * xFact ) - 1.0f;
-	npos.LowerRightCorner.Y = 1.0f - ( destRect.LowerRightCorner.Y * yFact ); 
+	npos.LowerRightCorner.Y = 1.0f - ( destRect.LowerRightCorner.Y * yFact );
 
 	video::SColor temp[4] =
 	{
@@ -1364,7 +1375,7 @@ void CD3D9Driver::setBasicRenderStates(c
 					mode=D3DTADDRESS_BORDER;
 					break;
 			}
-	
+
 			pID3DDevice->SetSamplerState(st, D3DSAMP_ADDRESSU, mode );
 			pID3DDevice->SetSamplerState(st, D3DSAMP_ADDRESSV, mode );
 		}

Index: source/Irrlicht/CD3D9Texture.h
===================================================================
--- source/Irrlicht/CD3D9Texture.h	(revision 982)
+++ source/Irrlicht/CD3D9Texture.h	(working copy)
@@ -10,6 +10,8 @@
 
 #include "ITexture.h"
 #include "IImage.h"
+#include "irrArray.h"
+#include "dimension2d.h"
 #include <d3d9.h>
 
 namespace irr
@@ -102,6 +104,12 @@ private:
 	void copy32BitMipMap(char* src, char* tgt,
 		s32 width, s32 height,  s32 pitchsrc, s32 pitchtgt) const;
 
+    //! Helper function for depthbuffer creation.
+	IDirect3DSurface9 *createDepthBuffer( D3DSURFACE_DESC& desc );
+
+	//! Helper function for depthbuffer update.
+	void updateDepthBuffer( );
+
 	IImage* Image;
 	IDirect3DDevice9* Device;
 	IDirect3DTexture9* Texture;
@@ -112,6 +120,9 @@ private:
 	s32 Pitch;
 	ECOLOR_FORMAT ColorFormat;
 
+	// static depthbuffer size storage for all rendertargets
+	static core::array< core::dimension2d<s32> > depthBufferSize;
+
 	bool HasMipMaps;
 	bool HardwareMipMaps;
 	bool IsRenderTarget;

Index: source/Irrlicht/CD3D9Texture.cpp
===================================================================
--- source/Irrlicht/CD3D9Texture.cpp	(revision 962)
+++ source/Irrlicht/CD3D9Texture.cpp	(working copy)
@@ -29,6 +29,10 @@ namespace irr
 namespace video
 {
 
+// static depthbuffer size storage
+core::array< core::dimension2d<s32> >	CD3D9Texture::depthBufferSize;
+
+
 //! rendertarget constructor
 CD3D9Texture::CD3D9Texture(CD3D9Driver* driver, core::dimension2d<s32> size, const char* name)
 : ITexture(name), Image(0), Texture(0), RTTSurface(0), Driver(driver),
@@ -97,6 +101,9 @@ HasMipMaps(false), HardwareMipMaps(false
 //! destructor
 CD3D9Texture::~CD3D9Texture()
 {
+    if( IsRenderTarget )
+        updateDepthBuffer();
+
 	if (Device)
 		Device->Release();
 
@@ -113,8 +120,28 @@ CD3D9Texture::~CD3D9Texture()
 
 void CD3D9Texture::createRenderTarget()
 {
-	TextureSize.Width = getTextureSizeFromImageSize(TextureSize.Width);
-	TextureSize.Height = getTextureSizeFromImageSize(TextureSize.Height);
+    // are texture size restrictions there ?
+    if( Driver->getCaps().TextureCaps & D3DPTEXTURECAPS_POW2 )
+    {
+        TextureSize.Width = getTextureSizeFromImageSize(TextureSize.Width);
+        TextureSize.Height = getTextureSizeFromImageSize(TextureSize.Height);
+
+        os::Printer::log("RenderTarget size has to be a power of 2",ELL_WARNING);
+    }
+
+    if( Driver->getCaps().TextureCaps & D3DPTEXTURECAPS_SQUAREONLY )
+    {
+        if( TextureSize.Width < TextureSize.Height )
+        {
+            TextureSize.Height = TextureSize.Width;
+        }
+        else
+        {
+            TextureSize.Width = TextureSize.Height;
+        }
+
+        os::Printer::log("RenderTarget size has to be of a square",ELL_WARNING);
+    }
 
 	// get backbuffer format to create the render target in the
 	// same format
@@ -157,7 +184,69 @@ void CD3D9Texture::createRenderTarget()
 	ColorFormat = getColorFormatFromD3DFormat(d3DFormat);
 
 	if (FAILED(hr))
-		os::Printer::log("Could not create render target texture");
+	{
+        if( hr == D3DERR_OUTOFVIDEOMEMORY )
+            os::Printer::log("Could not create RenderTarget texture: out of video memory");
+        else if( hr == E_OUTOFMEMORY )
+            os::Printer::log("Could not create RenderTarget texture: out of memory");
+        else
+            os::Printer::log("Could not create RenderTarget texture");
+
+        return;
+	}
+
+	// resize depthbuffer if necessary
+	IDirect3DSurface9* db;
+	if( !FAILED( Device->GetDepthStencilSurface(&db) ) )
+	{
+		D3DSURFACE_DESC desc;
+		db->GetDesc(&desc);
+
+		// need a new zbuffer ?
+		if( desc.Width < (u32)TextureSize.Width ||
+			desc.Height < (u32)TextureSize.Height)
+		{
+			// save current depth buffer size if this is the first render target
+			if( CD3D9Texture::depthBufferSize.size() == 0 )
+			{
+				core::dimension2d<s32> bs( desc.Width,desc.Height );
+				CD3D9Texture::depthBufferSize.push_back(bs);
+			}
+
+			// add this rendertarget size to list
+			core::dimension2d<s32> rts( TextureSize.Width,TextureSize.Height );
+			CD3D9Texture::depthBufferSize.push_back(rts);
+
+			// calculate useful depthbuffer size
+            core::dimension2d<s32> newSize(0,0);
+            u32 count = CD3D9Texture::depthBufferSize.size();
+            for( u32 i=0; i<count; ++i)
+            {
+                if( CD3D9Texture::depthBufferSize[i].Width > newSize.Width )
+                {
+                    newSize.Width = CD3D9Texture::depthBufferSize[i].Width;
+                }
+                if( CD3D9Texture::depthBufferSize[i].Height > newSize.Height)
+                {
+                    newSize.Height = CD3D9Texture::depthBufferSize[i].Height;
+                }
+            }
+
+            // create new depth stencil with same params like the old one, except the size
+            desc.Width = newSize.Width;
+            desc.Height = newSize.Height;
+            IDirect3DSurface9* newZBuf = createDepthBuffer( desc );
+
+            // replace old ZBuffer
+			if( newZBuf )
+			{
+			    Driver->setDepthBuffer( newZBuf );
+				newZBuf->Release();
+			}
+		}
+
+		db->Release();
+	}
 }
 
 
@@ -682,6 +771,89 @@ IDirect3DSurface9* CD3D9Texture::getRend
 }
 
 
+//! Helper function for depthbuffer creation.
+IDirect3DSurface9 *CD3D9Texture::createDepthBuffer( D3DSURFACE_DESC& desc )
+{
+    // create new depth stencil
+    IDirect3DSurface9* ZBuf;
+    HRESULT hr = Device->CreateDepthStencilSurface( desc.Width,
+													desc.Height,
+													desc.Format,
+													desc.MultiSampleType,
+													desc.MultiSampleQuality,
+													TRUE,
+													&ZBuf,
+													NULL);
+
+	if( hr == D3D_OK )
+		return ZBuf;
+	else if( hr == D3DERR_OUTOFVIDEOMEMORY )
+        os::Printer::log("Could not create DepthBuffer: out of video memory");
+	else if( hr == E_OUTOFMEMORY )
+        os::Printer::log("Could not create DepthBuffer: out of memory");
+    else
+        os::Printer::log("Could not create DepthBuffer");
+
+	return 0;
+}
+
+//! Helper function for depthbuffer update.
+void CD3D9Texture::updateDepthBuffer( )
+{
+    // remove current target size from list
+    u32 count = CD3D9Texture::depthBufferSize.size();
+    for( u32 i=0; i<count; ++i)
+    {
+        if( CD3D9Texture::depthBufferSize[i] == TextureSize )
+        {
+            CD3D9Texture::depthBufferSize.erase(i);
+            break;
+        }
+    }
+
+    // calculate useful depthbuffer size
+    core::dimension2d<s32> newSize(0,0);
+    count = CD3D9Texture::depthBufferSize.size();
+    for( u32 i=0; i<count; ++i)
+    {
+        if( CD3D9Texture::depthBufferSize[i].Width > newSize.Width )
+        {
+            newSize.Width = CD3D9Texture::depthBufferSize[i].Width;
+        }
+        if( CD3D9Texture::depthBufferSize[i].Height > newSize.Height)
+        {
+            newSize.Height = CD3D9Texture::depthBufferSize[i].Height;
+        }
+    }
+
+    // check if resize depthbuffer is necessary
+    IDirect3DSurface9* db;
+    if( !FAILED( Device->GetDepthStencilSurface(&db) ))
+    {
+        D3DSURFACE_DESC desc;
+        db->GetDesc(&desc);
+
+        // need a new zbuffer ?
+        if( desc.Width > (u32)(newSize.Width+50) ||
+            desc.Height > (u32)(newSize.Height+50) )
+        {
+            // create new depth stencil
+            desc.Width = newSize.Width;
+            desc.Height = newSize.Height;
+            IDirect3DSurface9* newZBuf = createDepthBuffer( desc );
+
+            // replace old ZBuffer
+            if( newZBuf )
+            {
+                Driver->setDepthBuffer( newZBuf );
+                newZBuf->Release();
+                db->Release();
+            }
+        }
+        db->Release();
+    }
+}
+
 } // end namespace video
 } // end namespace irr
 
[EDIT] Here's an improvement I should have done from the beginning: instead of using a static array inside the CD3DTexture class it should be moved to the CD3DDriver class and made local. [/EDIT]
Last edited by vi-wer on Sun Oct 14, 2007 12:58 pm, edited 1 time in total.
bull
Posts: 36
Joined: Wed Sep 12, 2007 8:49 am
Location: s1Ng4p0R3

Post by bull »

Nice work but can I ask: what actually do you use this for? A super big shadow map?? A super big in-game mirror/monitor??
My name is bull, for we are many ...
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

Thanks for uploading the patch; great work!
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Ico
Posts: 289
Joined: Tue Aug 22, 2006 11:35 pm

Post by Ico »

bull wrote:Nice work but can I ask: what actually do you use this for? A super big shadow map?? A super big in-game mirror/monitor??
Not distorted fullscreen post processing etc. :) (You'll need a render target bigger than your screen resolution if you want to use 2^x textures.)
vi-wer
Posts: 93
Joined: Sun May 20, 2007 7:15 pm
Location: Germany
Contact:

Post by vi-wer »

bull wrote:Nice work but can I ask: what actually do you use this for? A super big shadow map?? A super big in-game mirror/monitor??
If you're refering to the target size I mentioned, it's just an example of what's possible. What's more important is that render targets sometimes have to have a certain size while the screen size can be selected by the user. Something like this could have caused conflicts before.
Actually I need them for a FF8-like game. I've got prerendered backgrounds and realtime objects which are rendered to an offscreen render target. Then only a certain part of that scene will be visible on the screen (that's where the main character is). And because the screen size of these scenes is always different it wouldn't have been possible to do this before.
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

Cheers man, get ready for some "super big shadow maps"
:D
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
Blade
Posts: 9
Joined: Wed Sep 05, 2007 4:07 pm

Post by Blade »

Hi vi-wer!
your rendertexture works fine, but i found 2 little errors in your code:

first: the compiler complains, that

Code: Select all

bool CD3D9Driver::setDepthBuffer(IDirect3DSurface9 *depthbuffer)
doesn't return a bool!

second: you should not Release the db pointer twice in
void CD3D9Texture::updateDepthBuffer( )
btw: i also downloaded the patch file from the tracker, but i couln't apply the file to my irrlicht checkout! SVN said there would be an error in line 35!
Kimundi
Posts: 11
Joined: Sun Apr 01, 2007 11:04 am

Post by Kimundi »

Any changes this goes into 1.5?
Image
[Sorry for possible bad English]
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Any chances? Yes, there are :)
Tex Pine
Posts: 5
Joined: Mon Nov 19, 2007 11:49 pm

Post by Tex Pine »

Could this code be ported to the DX8 device, or does it use DX9-only functions?

EDIT: I mean, I could try to make a DX8 version of it, but I don't know enough of DX to check if all functions used are retro-compatible
Post Reply