Access to back buffer

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

You've changed the layout of the virtual table by adding another virutal function to the interface. This makes the new dll binary incompatible with the old dll.

The solution is to rebuild Irrlicht (the lib and the dll) and then link your application to the new lib. When you run your program, you need to be certain that the new Irrlicht.dll is the one that is found. You can be sure this happens by putting the right Irrlicht.dll into the same directory as your executable.

Travis
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

Ok creating a usable IDirect3D9Texture with MSAA is indeed harder than I thought, it seems your method of copying from a multi sampled surface is the best solution.

I'm not convinced about copying from the back buffer though, I'll try to find a cleaner solution, here's what I have in mind:

- If the render target has multisampling support, create a multi sampled IDirect3D9Surface (Locking will be disabled in this case also.) AND a IDirect3D9Texture with RTT usage.
- When the render target is set, use the multi sampled surface.
- When another render target is set after that, perform a StretchRect copy straight to the texture surface.

This should work fine in most cases, with the slight memory overhead of having 2 copies, but it certainly beats rendering to texture twice the size of the original, this one only uses twice as much memory compared to quadruple.

Ok who am I kidding I think I'll just use your solution and call it a day. :P

I'll provide a patch for D3D and OGL implementations soon.
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
saigo
Posts: 25
Joined: Tue Apr 14, 2009 6:48 am
Contact:

Post by saigo »

Thank you vitek for your suggestion but of course I ensured both lib and dll are properly rebuilt. And yes this problem is due to change of virtual addresses table layout.

My question is "Why this $#%&*! table desyncs since all binaries and headers are OK ?"

To make sure, I prepared a clean environment on another machine, I deleted all the binaries of irrlicht engine, then rebuilt it, then rebuilt my libraries, then rebuilt my application. In this case everything built fine (no dll mistake, no debug/release mistake, etc...)

Moreover everything is versionned using SVN so I can see through CRC check that the binaries were properly modified (rebuilt).

Still the problem happens...



BlindSide your idea is good, I suggested to directly use the back buffer because if you create another AA render target for AA render purpose, in this case the back buffer originally created when device is created is kind of wasted. Moreover copying directly from the back buffer is nothing dangerous since it's just a normal surface.

Anyway I think your idea is better because like this the user can switch AA render / non-AA render on the fly if needed for particular cases.
saigo
Posts: 25
Joined: Tue Apr 14, 2009 6:48 am
Contact:

Post by saigo »

I found the problem... my fault... my apologizes...
No relationship with irrlicht.
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

I had an attempt at making an OpenGL variant so this could get included into Irrlicht, but I'm not having much luck. I had to add the BlitFramebuffer extension to COpenGLExtensionHandler.

There seem to be a million and one ways of doing a straight copy from the backbuffer to an FBO but this is probably the best way for modern cards, albeit some ATI cards don't support it. Maybe hybrid or someone could have a look over this:

Code: Select all

bool COpenGLDriver::copyBackBufferTo(ITexture* dest)
{
	if (dest->getDriverType() != EDT_OPENGL)
		return false;

	GLint oldFBO = 0;
	glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFBO);

	COpenGLTexture* tex = (COpenGLTexture*)dest;
	core::dimension2du bSize = this->getScreenSize();

	this->extGlBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
	this->extGlBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex->getOpenGLTextureName());

	glReadBuffer(GL_BACK);
	glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);

	this->extGlBlitFramebuffer(	0, 0, bSize.Width, bSize.Height,
											0, 0, bSize.Width, bSize.Height,
											GL_COLOR_BUFFER_BIT, GL_NEAREST);

	this->extGlBindFramebuffer(GL_FRAMEBUFFER, oldFBO);
	
	return true;
} 
Here's a link to the blitextensions patch, with adds the extGlBlitFramebuffer function to COpenGLExtensionHandler: http://irrlichtirc.g0dsoft.com/BlindSid ... sion.patch
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
saigo
Posts: 25
Joined: Tue Apr 14, 2009 6:48 am
Contact:

Post by saigo »

Sorry BlindSide I don't know that much about OpenGL so I'm afraid I can't be a help.

However something I added to my implementation that I forgot before and I would suggest you to add is a simple parameter check at begining of the function, such as :

Code: Select all

bool COpenGLDriver::copyBackBufferTo(ITexture* dest) 
{
    if (dest == NULL || dest->getDriverType() != EDT_OPENGL)
        return false;

    [...]
If you encouter troubles with the DirectX9 implementation, just post here and I'll try to help.
saigo
Posts: 25
Joined: Tue Apr 14, 2009 6:48 am
Contact:

Post by saigo »

arf, I encouter a new problem since I patched irrlicht by adding that copyBackBufferTo virtual method to IVideoDriver and CD3D9Driver.

I'm working on Windows XP with irrlicht 1.5 and DirectX9 implementation only.

Now when I minimize the application, no problem, but when I restore the window from the task bar, the application fails in the method CD3D9Driver::reset, and it's when trying to retrieve the surface description from the default surface :

Code: Select all

// restore screen depthbuffer
pID3DDevice->GetDepthStencilSurface(&(DepthBuffers[0]->Surface));
D3DSURFACE_DESC desc;
DepthBuffers[0]->Surface->GetDesc(&desc); // <== FAIL HERE
So I tried this :

Code: Select all

// restore screen depthbuffer
pID3DDevice->GetDepthStencilSurface(&(DepthBuffers[0]->Surface));
D3DSURFACE_DESC desc;
IDirect3DSurface9* surface = DepthBuffers[0]->Surface;

IDirect3DDevice9* tmp_device;
surface->GetDevice(&tmp_device); // <== FAIL HERE
surface->GetDesc(&desc); // <== FAIL HERE
Any of the both last call fail with something like segfault reading address 0xC0000005.
The address of the surface retrieved (DepthBuffers[0]->Surface) is correct and match with the one originally created during device creation.

So tha surface seems to be corrupted, BlindSide do you have the same problem with your OpenGL implementation ? did you perform some tests with the DirectX9 implementation ?

PS: According to irrlicht 1.5 changelog:
- Lost devices (as found with D3D) are properly handled now. So the screen can be resized or minimized without crashing the app.
Nox
Posts: 304
Joined: Wed Jan 14, 2009 6:23 pm

Post by Nox »

Well. For irrlicht textures etc. not for your own extention. You have to care about this with your own surface by yourself! Maybe you missed to Release() something or you have to wait for the reset.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Hmm, good point. You do keep the surfaces. Irrlicht will only handle those in the texture caches. Everything else is in your hand. You can use the DX debug settings to find out what is breaking.
saigo
Posts: 25
Joined: Tue Apr 14, 2009 6:48 am
Contact:

Post by saigo »

Actually I add my render target this way in my post-effect class constructor :

Code: Select all

m_RenderTexture = driver->addRenderTargetTexture(dim, "PPINTERMEDIARYRTT");
then delete it at the end of my application, in my post-process class destructor :

Code: Select all

driver->removeTexture(m_RenderTexture);
though in my case the destructor is not called because application fails (by minimizing the window and restoring it) before it ends.
The surface which fails in the reset method is not my render target but is the default surface, which is officially called the "implicit swapchain".

In my application I create several other render targets and until then I never got any problem when minimizing the application window.
saigo
Posts: 25
Joined: Tue Apr 14, 2009 6:48 am
Contact:

Post by saigo »

OK today application fails at a different location... I reverted back my application code to previous version and it does not crash when minimizing, even with irrlicht modification I made.

In fact application crahes when minimizing if and only if I call driver->copyBackBufferTo(...) method.

I performed a test with exactly same code as when it crashes but commented out the call to copyBackBufferTo method and it works fine, well the main render displays graphic card memory garbage instead of proper render but over that garbage the UI and menus are properly rendered, which means the default surface is fine, and the application does not crash when minimizing.

So only that call to copyBackBufferTo makes the application to crash.

Any idea ? I don't use any thread in my application so is there a chance that irrlicht resets the device while in the middle of [DirectXDeviceInstance]->StretchRect (in the copyBackBufferTo method) ?
(I don't know about irrlicht actions perform timing)

Is there a way for me to protect the code from this problem ?

Thank you very much in advance for you precious help.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Just as Nox mentioned, you access the Surface in that method, and you have to release it after copying. Otherwise the reset will fail due to the surface being locked.
saigo
Posts: 25
Joined: Tue Apr 14, 2009 6:48 am
Contact:

Post by saigo »

Thank you very much everybody, I could fix the bug and now it works fine :)
So I post the DirectX 9 implementation again hoping it can help somebody else after me.

Code: Select all

bool CD3D9Driver::copyBackBufferTo(ITexture* dest)
{
	if (dest == NULL || dest->getDriverType() != EDT_DIRECT3D9)
		return (false);

	CD3D9Texture* tex = (CD3D9Texture*)dest;
	IDirect3DSurface9* destSurface = tex->getRenderTargetSurface();
	if (destSurface == NULL)
		return (false);

	IDirect3DSurface9* backBuffer;
	if (pID3DDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer) != D3D_OK)
		return (false);

	if (pID3DDevice->StretchRect(backBuffer, NULL, destSurface, NULL, D3DTEXF_LINEAR) != D3D_OK)
	{
		// backBuffer->Release();  // <- not sure if this have to be done...
		return (false);
	}

	backBuffer->Release();

	return (true);
}
Please review and adjust accordingly to match irrlicht design, and then it could be good that admin/modo tag the topic as [resolved] or something.

Again, thank you very much to everybody for your help.
klaudia
Posts: 20
Joined: Thu Jun 18, 2009 2:39 pm

Post by klaudia »

when:

bool CD3D9Driver::copyBackBufferTo(ITexture* dest)

this feature will be release officialy? irrlicht1.8 ?
slavik262
Posts: 753
Joined: Sun Nov 22, 2009 9:25 pm
Location: Wisconsin, USA

Post by slavik262 »

I added this to CD3D9Driver and recompiled Irrlicht. However, it's giving me a linker error (the usual "unresolved external symbol"). Do I have to expose this function somehow?

Edit: After exposing this in IVideoDriver (which I'm aware is a bad practice since not all of the video drivers have this function, but I'm only using DX9 anyways), I got the function to return work.

Is there a better way to allow the linker access to the function?
Post Reply