Windows tooltips/menus hammer 2D drawing

This may have been asked before, but for the life of me I can’t find a fix or workaround. I have an app in Windowed mode, using ManagedImages for sprites that are animated with a Canvas using a BufferStrategy of 3. It hums along just lovely at about 300 fps until the off chance that the mouse “lingers” over an icon or anything that has a tooltip. Once that tooltip pops up frame rate goes to hell even if my main java window still has the focus. Once the tooltip’s time is up and goes away everything returns to normal. Menus hurt performance quite a bit as well outside of the app, but java menus within the program don’t. I’m not too concerned with the menus hammering drawing, but the tooltips are everywhere, the system clock, the taskbar, etc.

I’ve tried adding sun.java2d.ddforcevram=true and sun.java2d.translaccel=true as well as any other obscure 2D argument I can find to my VM arguments and none seem to make any difference at all.

I am using WindowsXP and JDK 1.4.2_02-b03. The video card is an NVidia 5200 using the latest 52.16 drivers. I can post any of my souce code if you think it might help, but I am just using a pretty general, frame-limiting animation loop using the Perf timer that has been discussed pretty extensively here in the Java2D forum. Images are created using gConfig.createCompatibleImage(width, height, Transparency.OPAQUE) Is this a pretty common problem, or am I missing something obvious or doing something wrong?

Thanks for any ideas. :slight_smile:

Try forcing tooltips and popup menus to use heavy weights (see the Javadocs). I’m guessing it is some interaction with the tooltip painting that is causing Java2D to “un-manage” some image. Maybe the nature of the drawing calls to do the tooltip cause the underlying surface to be shunted back to normal RAM? Just guessing.

Hi swpalmer,
I initially thought it could be a conflict with heavyweights and lightweights in java, but the real blow to performance are really all the external windows tooltips and menus that I have no control over from within Java. And the real kicker is when I add the flag “sun.java2d.noddraw=true”. Theoretically I should lose all hardware acceleration when that flag is enabled, but when I do so, there is no performance hit whatsoever from any external Windows XP controlled menu, tooltip or drawing. And what’s even better is that even though my total frames are less when that flag is enabled, my overall performance is more stable with sun.java2d.noddraw=true overall.

For some tangible numbers, with the default setting sun.java2d.noddraw=false my total fps will drop from over 300 fps to under 100 fps by just hovering my mouse over the system clock and allowing the tooltip to show.

With sun.java2d.noddraw=true, my total frames are at 150 fps and stay at 150 fps no matter what external windows tooltips or menus are being shown.

It would seem, then, that there is something terribly wrong with DirectDraw in Java2D in windowed mode. Perhaps directdraw cannot coexist peacfully with GDI? But if that’s the case, it seems to me sun.java2d.gdiblit=false would help matters when directdraw is enabled but it doesn’t help anything.

Anyway, I’m going to try to run Borland’s Optimizeit and see if I can spot anything. Any ideas on what I should be looking for?

OK, here’s the stack traces from OptimizeIt. The first one shows me leaving the mouse in one spot so that it doesn’t accidentally hit anything that might render a tooltip.


1.17% - 516 ms - java.awt.Component$BltBufferStrategy.show()
            0.16% - 72 ms - sun.java2d.SunGraphics2D.drawImage()
               0.16% - 72 ms - sun.java2d.SunGraphics2D.drawImage()
                  0.16% - 72 ms - sun.java2d.pipe.ValidatePipe.copyImage()
                     0.16% - 72 ms - sun.java2d.pipe.DrawImage.copyImage()
                        0.16% - 72 ms - sun.java2d.pipe.DrawImage.copyImage()
                           0.16% - 72 ms - sun.java2d.pipe.DrawImage.copyImage()
                              0.16% - 72 ms - sun.java2d.pipe.DrawImage.renderSurfaceData()
                                 0.16% - 72 ms - sun.java2d.pipe.DrawImage.blitSurfaceData()
                                    0.01% - 5 ms - sun.java2d.loops.Blit.getFromCache()
                                       0.01% - 5 ms - sun.java2d.loops.RenderCache.get()

In this second one I am simply hovering my mouse over the various icons in my taskbar.


82.91% - 34324 ms - java.awt.Component$BltBufferStrategy.show()
            82.63% - 34207 ms - sun.java2d.SunGraphics2D.drawImage()
               82.63% - 34207 ms - sun.java2d.SunGraphics2D.drawImage()
                  82.63% - 34207 ms - sun.java2d.pipe.ValidatePipe.copyImage()
                     82.63% - 34207 ms - sun.java2d.pipe.DrawImage.copyImage()
                        82.63% - 34207 ms - sun.java2d.pipe.DrawImage.copyImage()
                           82.62% - 34202 ms - sun.java2d.pipe.DrawImage.copyImage()
                              82.62% - 34202 ms - sun.java2d.pipe.DrawImage.renderSurfaceData()
                                 82.62% - 34202 ms - sun.java2d.pipe.DrawImage.blitSurfaceData()

There is more to the stack trace that I can show, but these seemed to be the most different in execution time. Is there anything to explain this?

Hmm… sounds like it is having problems getting a drawing context or something.

Where’s Trembovetski or Chet or one of those guys? They would likely be able to give the right answer.

Well, I’m back from Hawaii =)

I think this could be some kind of conflict between Java2D and the OS using Direct3D at the same time, causing context switching and all kinds of other bad stuff.

BTW, your monitor refresh rate isn’t set by any chance to 100hz?

Welcome back! I hope the fresh air and sunshine did you some good.

Anyway, my monitors refresh rate is set at 85Hz. However, since I last posted I’ve had the chance to run my code on two additional test machines, both of which are similarly configured to my own (WinXP, DirectX 9, 512+ MB memory, NVidia video cards with identical video drivers and greater than 2GHz CPUs) and although both take a hit when tooltips show, neither seems to suffer nearly as much as my development system. That said, the only real hardware difference my machine has that the other two do not is the use of Rambus system memory. Perhaps it has a hard time simply due to the high latency nature of Rambus and perhaps not. I wish I could test on another Rambus based system, but they have always been a little scarce and remain so especially now. However, even with this blatant, non-scientific shot in the dark, setting -Dsun.java2d.noddraw=true absolutely fixes any hits to my framerate resulting from Windows tooltips, so the problem is definitely in DirectDraw somewhere. Doesn’t make any sense to me. Perhaps it’s nothing more than “Wall of Weird” material. [EDIT] I.e. if you’re not familiar with Smallville, not something to forget about, but rather something you set to the side and look at every once in a while and say “Huh, that’s kinda weird” And then go back to your normal Java2D blissful routine until one day it decides to attack while you’re taking a swim by yourself in the high school gym in the middle of the night. [/EDIT]

wow!

I just tested the game im writing atm, and tooltips do indeed kill performance :o

Mine drops from a constant 60, down to 45 :-/

hmm, I just tested Q3 and UT.

Q3 uses ogl, and showed no degradation in framerate when the tooltip was active. (between 170 and 180fps)

UT was using D3D, and showed a significant (though not massive) degradation in framerate. (went from 8ms to render a frame, to 10ms)

Weird :-*

interesting phenomena; I hadn’t noticed this one before.

From the various descriptions of the problem (including all the flags you tried), it sounds like it’s some horrible (and unavoidable?) context-switching bottleneck. In particular, a tooltip or menu (especially with the translucent menu fade effect of win2k/XP) would be doing heavy GDI rendering. Meanwhile, Java2D is doing heavy DirectX rendering. Sometimes, depending on the hardware and driver, the context switch between these libraries can be quite horrible;
a real performance killer. We have run into similar situations inside of Java2D that we tried to fix (for example, when we used to use ddraw for hor/vert lines and GDI for diagonals it caused serious performance problems just due to the ctxt switching; we now use d3d when we can which seems to help that specific problem immensely).

By using translaccel and ddforcevram, you are telling us that yes, you really want to use DirectX for these operations. So the images/buffers stay cached in VRAM and we use the ddraw Blt engine or d3d texture engine to copy stuff around in hw. By using noddraw, you are ensuring that we do not such thing; all images/buffers live in the Java heap and we copy the bits down to the screen over the bus using GDI. The fact that there is no fps change when noddraw is present implies that our GDI copy coexists happily with the desktop GDI operations (another pointer toward painful context switching). The fact that you are seeing different behavior on different systems in another indicator that the problem is card/driver-based; perhaps the card on your original system just has a driver that’s horribly inefficient at context switching.

Unfortunately, I don’t have a fix for you. Our use of directX allows us to get the great frame rates you are getting by default (300 fps). But that approach apparently conflicts with basic desktop functionality because of GDI/DX coexistence problems on that configuration (my theory, boldly stated but completely unproven…). so I think you’ve already seen your choices clearly; either choose the higher frame rate which can unfortunately hiccup given other occurrences outside the app, or choose the lower non-hw-accelerated framerate that is apparently more desktop-compatible. Or got into fullscreen mode and avoid the issue.

Some things that occur to me that you can try (more for data-gathering purposes that any real workarounds…):

  • Try to force us to use ddraw locking to copy to the screen when ddraw is disabled. I would expect similar crummy results because we’re still forcing context-switching to occur (without the benefit of the higher frame rate of hw acceleration). To do this, use the flags:
    -Dsun.java2d.ddoffscreen=false
    -Dsun.java2d.gdiblit=false
    -Dsun.java2d.ddlock=true
    This combo tells us: don’t use ddraw for offscreen surface caching (but still use it for other operations), don’t use GDI to copy bits down to the framebuffer, do use ddraw to copy bits to the screen. note that this does not enable translaccel, so your alpha images will be in system memory.
    I’m thinking that your framerate would be about equal to (or possibly a little better than) your 150 fps number with noddraw set, but that it would suffer during the tooltip/menu situations.

  • Try changing your desktop effects to avoid translucency fades, or anything that smacks of GDI animation. This could avoid too much GDI/DX thrashing during these operations.

Good luck…

Chet.

Wow, thanks. The information and ideas are very much appreciated and more than I could have hoped for.

Anyway, part of the initial angst over this occurred when I suddenly realized that my new, cool, clever animation loop was neither cool nor as clever as I had hoped. It suffered considerably with this particular fluctuation of framerate. Thus, I was forced to take a hard look at it again and as a result, I’m happy to report my overall animation code seems to be much more solid now. I was able to incorporate some of Marcus_Persson’s excellent interpolation ideas from his descrete step timing loop thread as well as a few techniques from Jeff’s scroller example for controlling framerates.

Anyway, I have also been trying a few of the additional switches you suggested and so far results seem to be as you predicted. I didn’t notice any difference with -Dsun.java2d.noddraw=true coupled with:
-Dsun.java2d.ddoffscreen=false
-Dsun.java2d.gdiblit=false
-Dsun.java2d.ddlock=true

However, one interesting phonomena I noticed; if I remove the noddraw flag above, but leave the others there, all tooltips external to Java flicker wildly including those in the Windows toolbar. Tooltips internal to Java seem unaffected, though, and my framerate remains the same as noddraw=true in this case.

In any event, I’ve added a little dialog that will allow the user to turn off DirectDraw at the expense of some eye candy, if it is an issue for them and they are unwilling to tweak the fade effects in Windows which does seem to make a big difference. And with the excellent explanation and UT benchmarks (Thanks Abuse, it never occurred to me to try another DirectX application such as Unreal Tournament) I have some ammunition in the event that anyone actually notices the performance hit and calls me on it. 8)

Many thanks to all.

-Immudium

Immudium,

Glad you found some workarounds. Note that the flag combo I specified above was intended to be tried without the noddraw flag (which I see you tried as well); when you specify ddraw, we don’t do anything at all through directX. But with the flag combo listed (not including noddraw), we will use ddraw for locking the screen and copying the bits.

The lovely flickering you noticed in your test of these flags is exactly why we started using GDI to copy bits to the screen instead of ddraw; when we lock the screen and copy the pixels, GDI animation loops completely halt and those objects do not get painted to the screen during that lock/unlock period. This includes the fading menus as well as software cursors (on platforms without hw cursor support, such as most Matrox cards).

Anyway, glad to hear you’ve found some things to alleviate the situation. Good luck…