Game Development Community

T2D 1.0.2 DirectX Fix

by Ken Paulson · in Torque Game Builder · 04/22/2005 (6:01 pm) · 30 replies

In guiCanvas.cc, line 1079, uncomment this bit:
PROFILE_START(glFinish);
glFinish();
PROFILE_END();


Haven't dug into the code to see what the implications are, but it fixed things perfectly here. From a slow flickery mess to wonderful smoothness.
Page «Previous 1 2
#1
04/22/2005 (6:07 pm)
Um if anything that should make it run slower.

VERY weird.

That simply turns on profilling of the code block. glFinish is generally not used as the state swapps slow things down.

Thats interesting that it fixzes things.

If you leave the profile calls commented does it still work better? IE just uncomment the glFinish() call.

I think I read that one of the things in this update was the removal of glFinish calls which normally speeds things up.
#2
04/22/2005 (6:11 pm)
Quote:
- 14th April 05
- Removed "glFinish". Not needed and causes CPU stalls.

Melv's C++ changelog...
#3
04/22/2005 (6:12 pm)
Yeah, I'm guessing that more profiling isn't really what fixed the problem, and that it's more the glFinish call. I'm running out the door so I don't have more time to dig or play. In a super quick code search it appears that it calls d3d->BeginScene, so maybe the scene handling isn't being done properly without it. But that's all wild conjecture at this point.
#4
04/22/2005 (11:07 pm)
I'm not an OpenGL guy and I haven't been digging in this source for long, so take these observations with a grain of salt. Hopefully they help a more enlightened person to pinpoint exact problems/solutions.

I looked up glFinish and found this: The glFinish function blocks until all OpenGL execution is complete. I gather it's not necessary and is used to sync the GPU and CPU, thus the comments about removing it to smooth out CPU stalls. But in the D3D mapping it calls device->BeginScene which does something completely different. It just signals that a new scene has begin and it is required.

A frame should look like this:

device->BeginScene();

//Rendering for the current frame

device->EndScene();
device->Present();

But as near as I can tell, without that call in there the loop is just:

//Render current frame
device->EndScene();
device->Present();


Also, wd3dCreateContext calls BeginScene which isn't correct. It's doing the device initialization.

So it looks like the OpenGL->D3D mapping is actually the issue. glFinish probably should be removed when running under OpenGL, but BeginScene does need to get called at the start of the frame.

I hope this helps. I really wish I had more time to dig into the source.
#5
04/22/2005 (11:27 pm)
Ah woops, that was a mistake to remove the glFinish stuff. This needs to be there for the D3D layer to get sync'd up. We may be able to replace it with calls to glFlush in the future, but for now, the best solution is to just ifdef these calls.. leave them in on Windows and out on other platforms.

This will be in the 1.0.3 update. This is a known thing in Torque, we just accidentally let it through! I should've checked that out a bit more closely before we released 1.0.2.

Thanks for the report Ken.
#6
04/23/2005 (2:41 am)
Ooops.

The reason I felt confident to remove that was that I remember Clark Faggot doing the same previously. I just couldn't find his post.

Dang; next time I'll consult with Josh to see if there are any other strange dependancies before I make changes like that.

Sorry everyone.

- Melv.
#7
04/23/2005 (6:52 am)
Yeah Clark and many others have removed gl Finish. I've removed them too never knowing it affected D3D.
#8
04/23/2005 (7:35 am)
@Melv i have it bookedmarked.

www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=3730

Quote:1. glFinish. Go into guiCanvas.cc and get rid of the call to glFinish. It simply isn't needed. I've never been able to find any resource on the net or any book suggesting it should be used for real-time work. If you can find such a thing, let me know and I'll eat my hat. Removing this will improve framerates as much as 30% on low end machines. Note: even the "Before" framerates above had this optimization, so in a sense those numbers are understated.
#9
04/23/2005 (10:53 am)
Awesome! Thanks Chris!

- Melv.
#10
04/23/2005 (1:41 pm)
@Ken: Ken, your're a God-send, no really you are!:) Now this is what such a community is really for; Josh and Melv need people like yourself to lend an extra hand, especially as they are so busy and over-burdened. They can use all the exttra help they can get right now to make T2D a very powerful piece of Technology!:) Good stuff Ken!:)

@Josh and Melv: Who can really blame you for missing this, it's just a reality and a sad reflection of the overwhelming work the two of you have to face on a daily basis. But this is why we have guys like Ken come along to help out - and perhaps make things a little easier for the both of you!:) Besides, had it not been for version 1.02; we'd probably never get down to grips with the notorious performance quality issues so pervasive on low-end computers. Now that this can get addressed, then I think the competition will have something to really worry and complain about because none them will have a full-featured high-performance engine that will at the same time run just as well on low-end computers!:) Watch the droves of potential developers pour into this community once this is fixed in version 1.03!:) It will be the best technology available to the masses, guaranteed!:) Keep up the good stuff guys, we'll help however we can!:)
#11
05/12/2005 (1:32 am)
Here's my little hack to make sure that glFinish is only called on non-OpenGL sessions (like DX or whatever might be used down the road)....
if(dStricmp(Con::getVariable("$pref::Video::displayDevice"), "OpenGL") != 0)
   {
      PROFILE_START(glFinish);
      glFinish();
      PROFILE_END();
   }
I haven't tested this on DX since my hardware does not support it, but it seems to work great on OpenGL.

Try it out.
#12
05/12/2005 (8:16 am)
I think a better fix is to disassociate D3D's BeginScene from glFinish. I sent a more detailed email to Josh about it a little while ago (feels like a couple weeks, but I wouldn't bet money on it) but I haven't heard anything back. Maybe I'll post it here a bit later so others can try it out.
#13
05/12/2005 (8:46 am)
Thanks for that Bryan, will try it out soon and let you know how it works on my Windows based machine!:)

I look forward to seeing that fix Ken !:)
#14
05/19/2005 (6:12 pm)
Sorry I took so long to post this. This is what I sent to Josh a few weeks ago. Sorry for the lame formatting.

In guicanvas.cc (line 1080), comment out the call to glFinish.

In OpenGL2D3D.cc, line 5798:
comment out the call to BeginScene. From what I can tell glFinish does not map in any way to BeginScene it was probably done as a convenient hack a long time ago and never really looked at again.

In OpenGL2D3D.cc, line 6913 (wglSwapBuffers)
Add
g.m_d3ddev->BeginScene();

Should look like this:
g.m_d3ddev->EndScene();
while (g.m_pD3DX->UpdateFrame(g.m_doFlip ? 0 : D3DX_UPDATE_NOVSYNC) == DDERR_SURFACEBUSY) {}

g.m_d3ddev->BeginScene();



This way your OpenGL code path doesn't have glFinish blocking things up, but if someone does need it for some reason it won't have an unexpected impact on the D3D side. On the D3D side, you now have each frame properly bracketed by calls to Begin/EndScene. I tried it on a 2 different cards and it worked flawlessly.
#15
05/19/2005 (11:32 pm)
Does this result in any speed gains for OpenGL? (And DirectX?)
#16
05/19/2005 (11:52 pm)
Apparently removing the call to glFinish will speed things up for slower systems under OpenGL.

The Direct3D part of the fix is much more significant. Many cards will run VERY poorly and possible with strange artifacts without a fix.

The super quick fix listed at the top fixes DX but can hurt OGL, while this one is good for both. This isn't official though, so you'll want to test it for yourself.
#17
05/20/2005 (10:16 am)
Will this cause any issues during cleanup/shutdown since it leaves an unmatched BeginScene behind?
#18
05/20/2005 (11:05 am)
It shouldn't, BeginScene doesn't add a reference to the device, they just need to be paired for proper rendering.
#19
05/20/2005 (11:51 am)
Cool. Thanks, Ken.
#20
06/30/2005 (3:37 pm)
This really offends my heroic and moronic sense of design nitpicking ;p

from the dx docs:

Quote:
There should be at most one IDirect3DDevice9::BeginScene/IDirect3DDevice9::EndScene pair between any successive calls to present (either IDirect3DDevice9::Present or IDirect3DSwapChain9::Present). IDirect3DDevice9::BeginScene should be called once before any rendering is performed, and IDirect3DDevice9::EndScene should be called once after all rendering for a frame has been submitted to the runtime.

and

Quote:
You cannot embed scenes; that is, you must complete rendering a scene before you can begin another one. Calling IDirect3DDevice9::EndScene when IDirect3DDevice9::BeginScene has not been called returns an error value. Likewise, calling IDirect3DDevice9::BeginScene when a previous scene has not been completed with the IDirect3DDevice9::EndScene method results in an error.

Some drivers have issues if this rule isn't followed and I'm pretty sure if someone starts calling it from
all over for some reason its all gonna blow sky high as they get out of sync.

edit:
I would suggest replacng glFinish() with glFlush() (or whatever you wish to call it, perhaps with a bool flag) and for Dx implement it
as a call to BeginScene() and in OGL as a call to glFlush() based on the bool param.
endedit

And I hope I don't offend anyone but that file sure has some damn ugly code in it, 1000 odd line functions, and
even use of goto.

Ouch ;p

Now I understand it was probably done inside a very tight deadline and it works, so go ahead and ignore my uptight ranting ;p

Not to hack on your interim fix Ken, nicely spotted ;p

regards
neo
Page «Previous 1 2