Direct3d Multihead implementation

Discussion area about developing or extending OGRE, adding plugins for it or building applications on it. No newbie questions please, use the Help forum for that.
User avatar
Thieum
Gnome
Posts: 342
Joined: Wed Apr 26, 2006 5:13 pm
Location: Bordeaux, France
x 2

Direct3d Multihead implementation

Post by Thieum »

UPDATE:
The latest version of the patch is available on the OGRE bug tracker
It corrects the alf-tab crash


Hi ! :)

I am modifying the D3D9 rendersystem to support multihead
It is not very easy because all the windows must be created before creating the d3d device so I had to add a method in the abstract Ogre::RenderSystem and in Ogre::Root to create all the windows and render windows at the same time :

Code: Select all

	RenderWindowList D3D9RenderSystem::createMultiheadRenderWindows(WindowParameterList &windowParams)
	{

[...]

		RenderWindowList win;

		mActiveD3DDriver->setMultihead(true);

		win.push_back(new D3D9RenderWindow(mhInstance, mActiveD3DDriver, false));

		NameValuePairList newMiscParams;
		if(windowParams[0].miscParams == NULL)
		{
			windowParams[0].miscParams = &newMiscParams;
		}
		(*windowParams[0].miscParams)["noD3DRessources"] = "true";
		win[0]->create( windowParams[0].name, windowParams[0].width,
			windowParams[0].height, true,
			windowParams[0].miscParams);
		mPrimaryWindow = (D3D9RenderWindow *)win[0];

		for( int i = 1; i < adapterCount; ++i)
		{
			win.push_back(new D3D9RenderWindow(mhInstance, mActiveD3DDriver, true));

			NameValuePairList newMiscParams2;
			if(windowParams[i].miscParams == NULL)
			{
				windowParams[i].miscParams = &newMiscParams2;
			}

			(*windowParams[i].miscParams)["noD3DRessources"] = "true";
			(*windowParams[i].miscParams)["parentWindowHandle"] = 
				StringConverter::toString(reinterpret_cast<int>(static_cast<D3D9RenderWindow*>(win[0])->getWindowHandle()));
			(*windowParams[i].miscParams)["head"] = StringConverter::toString(i);
			win[i]->create( windowParams[i].name, windowParams[i].width,
				windowParams[i].height, true,
				windowParams[i].miscParams);
			mSecondaryWindows.push_back(static_cast<D3D9RenderWindow *>(win[i]));
			static_cast<D3D9RenderWindow*>(win[i])->buildPresentParameters();
		}


		for( int i = 0; i < adapterCount; ++i)
		{
			static_cast<D3D9RenderWindow*>(win[i])->createD3DResources();
			attachRenderTarget( *win[i] );
		}

[...]

return win;
}


the function returns a list of renderwindow, one per head

but the problem is that only one fullscreen window is refreshed because only one has the focus.
how can I force the other windows to be refreshed ?
change

Code: Select all

if( itarg->second->isActive() && itarg->second->isAutoUpdated())
in RenderSystem::_updateAllRenderTargets ?
or change WindowEventUtilities::_WndProc ?
I tried to comment the code associated with the WM_ACTIVATE message but it is dirty and the second screen flickers :/

do you have any solution ?

i can post a patch of my other changes. if it can help to add an official multihead support to ogre...
Last edited by Thieum on Tue Jul 15, 2008 8:41 am, edited 3 times in total.
User avatar
Thieum
Gnome
Posts: 342
Joined: Wed Apr 26, 2006 5:13 pm
Location: Bordeaux, France
x 2

Post by Thieum »

I have improved the code
now everything is working fine
I can have 2 fullscreen views with independant resolutions :D

the patch file to apply to ogre new
http://www.axyz-images.com/support/OGRE ... -patch.zip
it modifies Rendersystem_direct3D and OgreRoot

I have reworked a bit D3D9Renderwindows, now there are no more differencies between the primary window and the secondary windows, they are both swap chains

I still use a workaround to have the two screens refreshed each frame
(and not only the one which is associated to the focused window) :
in OgreEventUtilities.cpp

Code: Select all

	case WM_ACTIVATE:
	{
		bool active = (LOWORD(wParam) != WA_INACTIVE);
		//win->setActive( active ); /* disabled */  
		for( ; start != end; ++start )
			(start->second)->windowFocusChange(win);
		break;
	}
I think i will use WindowEventListeners to "propagate" the focus
Last edited by Thieum on Wed May 28, 2008 10:26 am, edited 1 time in total.
Chaster
OGRE Expert User
OGRE Expert User
Posts: 557
Joined: Wed May 05, 2004 3:19 pm
Location: Portland, OR, USA

Post by Chaster »

Cool! Have you officially submitted this as a patch? To do so, go to the main ogre page (www.ogre3d.org) and click on "Developers" then "Submit a Patch"

Chaster
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66

Post by sinbad »

Yes, definitely please do this - both to ensure this doesn't get buried in the forum, and because we need a contributor license agreement from you before this can be accepted.

Thanks!
User avatar
Thieum
Gnome
Posts: 342
Joined: Wed Apr 26, 2006 5:13 pm
Location: Bordeaux, France
x 2

Post by Thieum »

I am glad you appreciate my contribution :)

I have resolved the focus problem (only one screen was refreshed because only one window had the focus) by adding a WindowEventListener to the main window which sets active the other windows.
But this listener is added from the application and not from ogre. Do you think it would be better to add this listener directly in Root::createMultiheadWindows ?

I am also preparing the patch for submission. I used Ogre 1.4RC1 for the implementation but I will verify it works also with Ogre 1.4. But shall I use the cvs head revision (Shoggoth) as it is said in "Submitting a Patch" or just the latest Eihort release to make the patch ? (I am not really at ease with submissions :o )
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66

Post by sinbad »

They will be pretty much the same barring any small delayed merge issues since Eihort hasn't been stable long. I'll decide which branch to apply it to depending on the significance of the change.
User avatar
Thieum
Gnome
Posts: 342
Joined: Wed Apr 26, 2006 5:13 pm
Location: Bordeaux, France
x 2

Post by Thieum »

patch submitted
willthrom
Gnoblar
Posts: 9
Joined: Thu Feb 21, 2008 8:37 am

Testing

Post by willthrom »

I don't know if it's the right thread but I'm testing the last patch from

http://sourceforge.net/tracker/index.ph ... tid=302997

with CVS 1.4.6.

Problems:

*GL subsystem doesn't compile.
*Directx Rgb Option was eraser in code but Ogre Graphic menu return this option.
*When I try to run a app with multihead and using PageGeometry it crash. with a log message in ogre.log

08:47:27: OGRE EXCEPTION(0:IOException): Unknown RenderSystem color format in BatchedGeometry::SubBatch::addSubMesh() at ogre\pagedgeometry_v1.03_vc80\pagedgeometry\source\batchedgeometry.cpp (line 308)
VertexElementType format = Root::getSingleton().getRenderSystem()->getColourVertexElementType();

Code: Select all

switch (format){
			case VET_COLOUR_ARGB:
				std::swap(newMesh.color.r, newMesh.color.b);
				break;
			case VET_COLOUR_ABGR:
				break;
			default:
				OGRE_EXCEPT(0, "Unknown RenderSystem color format", "BatchedGeometry::SubBatch::addSubMesh()");
				break;
	}

PD: Sorry for my english :(
User avatar
Thieum
Gnome
Posts: 342
Joined: Wed Apr 26, 2006 5:13 pm
Location: Bordeaux, France
x 2

Post by Thieum »

Yes, it's the right thread :)
The patch was not tested with other ogre addons, I will try PageGeometry.
*Directx Rgb Option was eraser in code but Ogre Graphic menu return this option.
Can you give more details about this problem ?
willthrom
Gnoblar
Posts: 9
Joined: Thu Feb 21, 2008 8:37 am

Post by willthrom »

First... Do i apply the patch to right MainOgre version? CVS 1.4-6.

OpenGL subsystem compile right.

In PageGeometry in file BatchedGeometry.cpp method addSubMesh and build, these functions call the function Root::getSingleton().getRenderSystem()->getColourVertexElementType(). the returned value is out of range.

== default:
OGRE_EXCEPT(0, "Unknown RenderSystem color format", "BatchedGeometry::SubBatch::addSubMesh()");
break;

To pass the problem I remove exception and add std::swap(newMesh.color.r, newMesh.color.b); because D3D subsystem use RGB but PageGeometry addon only work with Grass,, tree exploit (for now)
User avatar
Thieum
Gnome
Posts: 342
Joined: Wed Apr 26, 2006 5:13 pm
Location: Bordeaux, France
x 2

Post by Thieum »

I tried the examples of PagedGeometry with the patch (multihead_wip2.patch) applied on the latest 1.4.6 cvs branch and they work fine on two screens. How do you create the RenderWindows ? I used the same code I provided in the example based on Demo_Fresnel

I don't really know where the bug can came from because the patch doesn't touch anything about color formats. If you revert the patch, does it work fine ?

edit (04/04/08) : I updated the example of the Stereovision manager and it now supprts multihead. Prefer this example because it is better documented. Just uncomment #define MULTIHEAD and press U to enable dual output stereo

edit (05/28/08) : How to apply the patch (copypasta from another post)
You will need a program to apply the patch, I used GNU patch
Copy patch.exe in c:\windows\ (it may not be the best solution but it is the simplest)
Copy the patch in the orgrenew folder, open a command window here and use this command :

Code: Select all

patch -p0 -i multihead_wip2.patch
Last edited by Thieum on Wed May 28, 2008 10:32 am, edited 2 times in total.
User avatar
toglia
Gnome
Posts: 336
Joined: Sat Dec 08, 2007 4:28 am
Location: Canada
x 7

Post by toglia »

I'm trying to install the patch on Ogre 1.4.6 and this is what I have done:

1) Downloaded the "multihead_wip2.patch" on:
http://sourceforge.net/tracker/download ... id=1692979

2) Downloaded Ogre's 1.4.6 Source code:
http://sourceforge.net/project/showfile ... up_id=2997
ogre-win32-v1-4-6.zip

3) Downloaded GNU patch "patch-2.5.9-7-bin":
http://gnuwin32.sourceforge.net/downlin ... in-zip.php

4) Copied patch.exe on C:\Windows

5) Copied "multihead_wip2.patch" on C:\ogrenew

6) On console:
C:\ogrenew> patch -p0 -i multihead_wip2.patch

7) Opened the RenderSystems\Direct3D9 project and rebuilt it on release mode, but I'm getting:

Code: Select all

Error	98	error LNK2001: unresolved external symbol "__declspec(dllimport) public: void __thiscall Ogre::RenderSystemCapabilities::setNumAdapters(unsigned short)" (__imp_?setNumAdapters@RenderSystemCapabilities@Ogre@@QAEXG@Z)	OgreD3D9RenderSystem.obj	

Error	99	fatal error LNK1120: 1 unresolved externals	c:\Users\Alberto Toglia\ogre-win32-v1-4-6\ogrenew6\lib\RenderSystem_Direct3D9.dll	
I had tried Compiling the "RenderSystem_Direct3D9" project before the patch and I was able to create the lib, exp and dll files successfully, after the patch I'm just creating the lib and exp files along with the errors above...

Now I really don't know where to look.

Thanks for any help.
User avatar
Thieum
Gnome
Posts: 342
Joined: Wed Apr 26, 2006 5:13 pm
Location: Bordeaux, France
x 2

Post by Thieum »

have you also recompiled OgreMain ? the patch adds a few methods here too
(setNumAdapters for example)
User avatar
toglia
Gnome
Posts: 336
Joined: Sat Dec 08, 2007 4:28 am
Location: Canada
x 7

Post by toglia »

I will! Thanks! Is it working with Eihort 1.4.7?
User avatar
Thieum
Gnome
Posts: 342
Joined: Wed Apr 26, 2006 5:13 pm
Location: Bordeaux, France
x 2

Post by Thieum »

yes the latest version of the patch was created from ogre 1.4.7
TMT
Halfling
Posts: 59
Joined: Thu Aug 23, 2007 8:09 pm

Post by TMT »

I should mention two problems with Ogre and this patch regarding multiple displays and gfx cards.

First, I found that with Ogre and the D3D9 rendering system, if you have multiple displays, even on the same gfx card, Ogre doesn't distinguish the names of the displays when it enumerates them. That's not a problem with this patch when you have a single gfx card, but it is a problem if you have two of the exact same gfx cards because all displays have the same name. Ogre will always match the first display and hence the first gfx card, so trying to select the second gfx card is impossible. I solved this temporarily in my code set by adding an ordinal number to each enumerated display name, so that each display name is unique. Eventually I want to explicitly allow selection of the gfx card number and the display number (e.g. card 2, display 1). The info is there in D3D, but it just needs to get added to the generated names. As I stated, this is really a problem with Ogre and not this patch (and I think there is a patch out there that even fixes this in some fashion other than I mentioned).

Second, the patch expects a window definition for every display in the system, even for multiple gfx cards, but D3D9 will not allow a single device instance to work across multiple gfx cards. In other words, if you have two gfx cards, each with two displays attached, this patch expects four window definitions, but it will fail to create the D3D9 device. So this patch needs to be patched to expect the number of render window definitions equal to the number of displays on the selected gfx card. This display number must be checked and validated in D3D9RenderSystem::createMultiheadRenderWindows() and then the stored for later use in D3D9RenderSystem::createDevice() for the multihead section.

I've been meaning to post this info and a patch, but I've been caught up in other work for a while haven't found the time to finish it out. My patches are not complete either. But in the end I intend calls to createMultiheadRenderWindows() be allowed to specify which gfx card to use and then internally validate the number of window definitions against that card's number of displays.

Just to clarify, this patch works fine if you have a single card. But the minute you install a second card, there will be trouble.
User avatar
toglia
Gnome
Posts: 336
Joined: Sat Dec 08, 2007 4:28 am
Location: Canada
x 7

Post by toglia »

Got it working! Thanks for your help! Very very cool patch.

One thing though, I getting a crash on line:

Code: Select all

mTargetWindow->setActive(rw->isActive());
when exiting the program. (Weird right).

Do I have to exit the program some specific way?

Thanks again.
User avatar
Thieum
Gnome
Posts: 342
Joined: Wed Apr 26, 2006 5:13 pm
Location: Bordeaux, France
x 2

Post by Thieum »

Oops, there is a bug here. If mTargetWindow is destroyed before the first one (which has the listener), the pointer becomes invalid.

try to replace the WindowEventListener by this :

Code: Select all

	/*** Multihead : Listener used to give the focus to the second window when the first one receives the focus*/
	class MultiheadListener : public WindowEventListener
	{
	public:
		RenderWindow *mTargetWindow;
		MultiheadListener *mTargetListener;
		MultiheadListener() : mTargetWindow(NULL), mTargetListener(NULL) {}
		void windowClosed(RenderWindow* rw)
		{
			if(mTargetListener)
			{
				mTargetListener->mTargetWindow = NULL;
				mTargetListener->mTargetListener = NULL;
			}
		}
		void windowFocusChange (RenderWindow *rw)
		{
			if(mTargetWindow)
				mTargetWindow->setActive(rw->isActive());
		}
	};

	MultiheadListener mFocusListener0;
	MultiheadListener mFocusListener1;
and the code adding the listener by this :

Code: Select all

			// tells the listener of the first window to change the focus of the second
			// window when the focus of the first windows has changed
			mFocusListener0.mTargetWindow = mWindows[1];
			mFocusListener0.mTargetListener = &mFocusListener1;
			WindowEventUtilities::addWindowEventListener(mWindows[0],&mFocusListener0);
			// gives the focus to the second window because when created, only the first window has the focus
			mFocusListener0.windowFocusChange(mWindows[0]); 

			// this listener will just inform the other listener that the second window 
			// has been destroyed and that it shouldn't change its focus
			mFocusListener1.mTargetWindow = NULL;
			mFocusListener1.mTargetListener = &mFocusListener0;
			WindowEventUtilities::addWindowEventListener(mWindows[1],&mFocusListener1);
I have not tested this code a lot because I never experienced your bug. If it corrects your bug, i will change the code in the zip file :)

TMT> Thanks for the feedback!
I planned to test the patch with two graphic cards, but i was never able to do it. I only have one pci-express port on my computer and it is difficult to find a dx9 pci graphic card. (I bought an ati 9200 but it doesn't work with a nvidia card)
About the problem of the number of adapters expected by the patch, it should not be very difficult to fix. But I'm also very busy at the moment. I will try to find some time to fix this.
How do you planned to specify the card to use ? maybe by using a miscParam. It is per window, not per "card" or per "call" but it could work.
User avatar
toglia
Gnome
Posts: 336
Joined: Sat Dec 08, 2007 4:28 am
Location: Canada
x 7

Post by toglia »

I have found this crash doesn't happen if I use the Example Application framework, but on the other projects I have I still get the same crash even with the modification. I will check what could be happening, but for now I have no idea... :(

If you would like to repeat the crash I think you could try compiling and running this cpp (super small code to run a multihead basic Ogre d3d application with nothing on it, based on nullsquared soft shadow demo)

http://toglia.com.ve/code/main.cpp

It doesn't have media at all, and it should execute ok using D3d.

Another thing, how do you debug when using the createMultiheadRenderWindows method?, I can't get out of the fullscreen...
TMT
Halfling
Posts: 59
Joined: Thu Aug 23, 2007 8:09 pm

Post by TMT »

toglia,
I have found that if I put a break point at these lines in D3D9RenderWindow::create(), then stop over them (F10), then I can continue to debug fine after that:

Code: Select all

		if(!noD3DRessources)
			createD3DResources();
User avatar
gerds
Goblin
Posts: 260
Joined: Mon Sep 01, 2003 3:59 am
Location: London, United Kingdom
x 1

Post by gerds »

FYI: I've applied the "sinbad" patch to ogre 1.4.9 and it seems to work fine (apart from the crashing after alt-tab or changing back and forth to fullscreen).

We only need multihead fullscreen windows and can live with the inability to alt-tab (although this is a little painful) so thanks everyone for your work on this so far.
User avatar
Thieum
Gnome
Posts: 342
Joined: Wed Apr 26, 2006 5:13 pm
Location: Bordeaux, France
x 2

Post by Thieum »

the alt-tab bug should have been fixed
have you applied the latest version of the patch available on sourceforge ?
( http://sourceforge.net/tracker/index.ph ... tid=302997 )
speedwago
Gnoblar
Posts: 17
Joined: Sun Aug 13, 2006 10:39 am

Post by speedwago »

the patch does not work with version 1.6

will be upgraded?
User avatar
Thieum
Gnome
Posts: 342
Joined: Wed Apr 26, 2006 5:13 pm
Location: Bordeaux, France
x 2

Post by Thieum »

yes, i will upgrade it
but i don't have a second screen at home, and i don't have really time to work on it at my office :?
so it may take some time
MattStevens
Goblin
Posts: 239
Joined: Mon Apr 07, 2008 10:27 pm
x 4

Post by MattStevens »

I have a few questions regarding the multihead patch.

First of all, this is for full screen only, right ? When in windowed mode you can use multiple calls to Root::createRenderWindow to create x numbers of windows.

Also, even for fullscreen, I don't see the use for it. With NVidia you can span a single window on 2 screens with a resolution of like 2048 * 768 and it works like a charm. I believe you can do the same with 4 screens and 2 cards on SLI mode, right ? If so, I do not get the point of having to handle 2 (or more) render windows seperatly. Does it give a performance boost ?

We are currently looking to support many full screen windows, and we want to make sure we have everything working and ready before starting a project.

- Matt Stevens