Multiple viewports/multiple monitors... DirectX doesn't like

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!
Post Reply
death_au
Posts: 38
Joined: Tue Apr 17, 2007 9:48 am
Location: Australia

Multiple viewports/multiple monitors... DirectX doesn't like

Post by death_au »

I've been looking around the forums and looking at different solutions for rendering things to multiple monitors. One option seems to be to create two windows on the separate monitors, and pass their id to endScene()
The option I prefer is the multiple viewports on the one window, which is stretched over the two monitors. It seems to work, except that DirectX doesn't want to render textures properly, except on the final viewport.

This is the kind of code I'm using:

Code: Select all

device = createDevice(video::EDT_DIRECT3D9, core::dimension2d<s32>(2560, 1024));
	
smgr=device->getSceneManager();
driver=device->getVideoDriver();
env=device->getGUIEnvironment();

//...some misc setup code

while(device->run())
if(device->isWindowActive())	
{
	driver->beginScene(true, true, SColor(0,0,0,0));

	driver->setViewPort(rect<s32>(0,0,1280,1024));
	smgr->drawAll();
	// some code...
	env->drawAll();

	driver->setViewPort(rect<s32>(1280,0,2560,1024));
	smgr->drawAll();
	// some code...
	env->drawAll();

	driver->endScene();
}
device->drop();
The textures on the first viewport don't render properly. In fact, most of the time they don't render at all. But on the second viewport, everything works fine. I also had this problem on the tank project I was working on earlier, but we decided to just render it in OpenGL and be done with it; the problem does not occur in OpenGL.
However, we have some features of our models on this project (such as shininess factors) that the OpenGL renderer doesn't seem to support well and would prefer to use DirectX.

I tried wrapping each viewport in beginScene()/endScene() calls seperately (as opposed to just one beginScene() and one endScene()) and that almost worked, but the viewports then just flashed horribly... Lucky I'm not epileptic :P

So, does anyone have any ideas on why DirectX doesn't like the multiple viewports? And more importantly, how can I fix it?
Image
death_au
Posts: 38
Joined: Tue Apr 17, 2007 9:48 am
Location: Australia

Post by death_au »

Sorry for double-posting, but I was playing around a bit, and I got something to work... Kind of.
I put a beginScene() call for every viewport, setting the viewport before I actually call beginScene(), so now my code looks like this:

Code: Select all

device = createDevice(video::EDT_DIRECT3D9, core::dimension2d<s32>(2560, 1024));
   
smgr=device->getSceneManager();
driver=device->getVideoDriver();
env=device->getGUIEnvironment();

//...some misc setup code

while(device->run())
if(device->isWindowActive())   
{
   driver->setViewPort(rect<s32>(0,0,1280,1024));
   driver->beginScene(true, true, SColor(0,0,0,0));
   smgr->drawAll();
   // some code...
   env->drawAll();

   driver->setViewPort(rect<s32>(1280,0,2560,1024));
   driver->beginScene(true, true, SColor(0,0,0,0));
   smgr->drawAll();
   // some code...
   env->drawAll();

   driver->endScene();
}
device->drop();
The screens are now rendering fine, but the console is constantly spitting out "DIRECT3D9 Begin Scene failed!" That's correct I suppose. The scene was not ended before the new scene was begun, so it should give me that error. What I'm confused about, is that it obviously did do something, because now the textures are rendering properly.

Some more poking around revealed that the graphics problem is that the z-buffer is being disabled when the viewport is changed. i.e. if I call...

Code: Select all

driver->beginScene(true, false, SColor(0,0,0,0));
...I get the same graphical glitching as the viewports do. Don't know if that helps in anyway, but it's what I found out.

So for now, I'm going to leave the code as is, and put up with the console spewing out errors... It's not like the user will see the console anyway. But I do still want a better solution, if one exists.
Image
wetfire
Posts: 10
Joined: Wed Aug 30, 2006 12:10 pm
Location: Italy

Post by wetfire »

Hi I solve this problem just adding driver->clearZBuffer(); after each smgr->drawAll();

I hope this was useful
Nothing is impossible!

My photolog
Thulsa Doom
Posts: 63
Joined: Thu Aug 05, 2004 9:40 am
Location: Germany

Post by Thulsa Doom »

Hello death_au
The option I prefer is the multiple viewports on the one window
Me too, otherwise one would have to fight with multiple devices and moreover with multiple threads to get it work.

I've already encapsulated the code it in two classes CMainScene and CViewPort.
Yes it works in DirectX only :x
How do you manage the event handling with the different cameras?

Here is my solution:

Main.cpp

Code: Select all

	CMainScene scene(device,&emgr);
		scene.setDimensions(displayDimensions);

	CViewPort viewport1(device,&emgr);
		viewport1.setPosition(core::position2di(300,400));
		viewport1.setDimensions(dimension2d<s32>(400,400));

	CViewPort viewport2(device,&emgr);
		viewport2.setPosition(core::position2di(0,0));
		viewport2.setDimensions(dimension2d<s32>(400,400));

	while(device->run())
	{
		
		driver->beginScene(true, true, SColor(128,4,4,16));
	
		scene.render(driver);
		scene.reset(driver);
		viewport1.render(driver);
		scene.reset(driver);
		viewport2.render(driver);
		
		/*
		guienv->drawAll();
		*/

		driver->endScene();
	}
	
	...
with the core functions

CMainScene.cpp

Code: Select all

	void CMainScene::render(IVideoDriver* driver)
	{
		driver->setViewPort(mViewPort);
		mSmgr->drawAll();
	}

	void CMainScene::reset(IVideoDriver* driver)
	{
		driver->setViewPort(mViewPort);
		driver->clearZBuffer();
	}
CViewPort.cpp

Code: Select all

	void CViewPort::render(IVideoDriver* driver)
	{
		driver->draw2DRectangle(SColor(128,64,128,64), mViewPort); 
		driver->setViewPort(mViewPort);
		mSmgr->drawAll();
	}
The mViewPort is alway a local member variable
which holds the core::rect<s32> of each port.
Post Reply