So, this is a call to action: Please try your applications with this new pipeline and let us know if you find any issues. We really want to make this pipeline rock-solid as it needs to be if it is to be left enabled by default. Time is short, so the sooner you report issues the better chances are we'll have time to fix them.

One issue may be that since it is not possible to render directly to the screen in Direct3D9 we have this emulated mode wherewe redirect all on-screen rendering to an off-screen 'buffer strategy-like thingie' which is then flipped by another thread once in a while. Normallythe update thread wakes up every 100ms, unless you copy a VolatileImage to the screen, in which case we take it as aclue that you want to see the results on the screen now.

So the delay you are be seeing could be that.

You can get the best performance by using BufferStrategy insteadof a VI as a back-buffer approach with the D3D/OGL pipelines.

Also, how do Swing apps look on your 945G?Each Intel chip is full of surprises =)

As a clue, the (BufferedImage).flush() is not impl.. So BufferedImage never flushes itself. Solely called from the ImageConsumer , the buffer is cleared when the source is cleared. As a fact, if your image is Volatile, then nothing will be drawn since the ImageConsumer's have flushed themselves, that is the contract of VolatileImage. But when your Thread sleeps for 100ms, those milliseconds of time ARE LOST indeed, because it could have been time to load further images. That is to Thread an extra process to load up all or part of your buffer concurrently to paint on screen. Then somehow validate your buffer to make the paint method occur when needed.That has no impact on how you use the pipeline, activated or not, it is thoroughly NOT recommended to flush() your buffer PRIOR to paint, but you may eventually overflow on your heap space if the screen is not well tiled. So TILES are a good solution to make accurate updates on screen. Where Tiles can bring improvements, I ain't focusing the discussion on them, because I don't use them. I prefer to VALIDATE my buffer and to draw only when my buffer is valid and to clear it when it is not valid or overflow is detected. Then the faster the buffer is to load itself, the lesser frames will be skipped. I would say to simply erase any Thread sleeps and to have a variable Timer based on the Swing framework, as the Timer's can be of a variable delay. because 100 ms are a 10 frames per seconds and if you want a 30 FPS then the Timer could vary from 0 - 100ms to regulate rendering events.

That is what I'm talking about, improved double buffering and Thread-safe buffer management (where (Image).flush() must be handled with caution (!)). The latter of these concepts is left to your own to implement or not.

Is there a way to detect, at runtime, if the Direct3D 9 pipeline is enabled? (For example, a system property that can be detected in an Applet's sandbox)

In Milpa (using PulpCore, which uses regular repaint() requests on Windows, and runs at 60fps), I noticed a few dropped frames, but not many. Oddly, I noticed occasional "half-frame" updates - the left side of the applet would occasionally be one frame ahead of the right side. This is on a Mobility Radeon 9600.

When I use -Dsun.java2d.d3d=false, the problem goes away. Without a doubt, the animation looks a lot better with the flag set to false.

in regard to painting on screen, I've some to share if you want some : there's the rendering scene (actually the std Canvas extended with GraphicsJAI instances) to manage overall painting, both passive and active :

What I mean is, is there a way to programmatically detect, at runtime, if the D3D9 pipeline is used?

If so, for existing games, at runtime the engine can use new code (using BufferStrategy) on the D3D9 pipeline, but stick with the old code (repaint()) on other pipelines (which I know already works fine on Java 1.4, Java 1.5, and the current Java 6 on Windows, on a wide variety of hardware).

Because if I had to switch to using new rendering code for all Java VMs, that creates a lot of QA work. So right now I only want to switch to new rendering code if the user has the D3D9 pipeline. (The alternative is to "guess" the VM is using D3D9 by checking if the version number is 1.6.0_05 - hairy stuff.)

in regard to painting on screen, I've some to share if you want some : there's the rendering scene (actually the std Canvas extended with GraphicsJAI instances) to manage overall painting, both passive and active :

Thanks. Even after studying the code I'm not quite sure how it acts to sync painting with the screen refresh... is it somehow using the BufferStrategy to find out when the screen's ready to paint?

One issue may be that since it is not possible to render directly to the screen in Direct3D9 we have this emulated mode wherewe redirect all on-screen rendering to an off-screen 'buffer strategy-like thingie' which is then flipped by another thread once in a while. Normallythe update thread wakes up every 100ms, unless you copy a VolatileImage to the screen, in which case we take it as aclue that you want to see the results on the screen now.

So the delay you are be seeing could be that.

You can get the best performance by using BufferStrategy insteadof a VI as a back-buffer approach with the D3D/OGL pipelines.

Hi Dmitri, why does this update thread only wake up every 100ms? That only 10FPS. Of course I'm sure that you've investigated, but why do we need this intermediating update thread for D3D, we didn't have it in the old pipeline and I assume that non-java D3D apps don't have it.

Great to see the improvements made to the D3D pipeline. however its a bit dangerous in my mind to release it that shortly before the targeted release of the consumer-jvm. I'll test all my apps to see whats happening...I always dreamed the OpenGL pipeline would be default on windows and all drivers would have to be compatible

Is there a way to detect, at runtime, if the Direct3D 9 pipeline is enabled? (For example, a system property that can be detected in an Applet's sandbox)

Unfortunately there isn't. As of now the sun.java2d.d3d property is set to 'true' by defaultand you can check it but it doesn't guarantee that the pipeline is enabled.

Another clue is to check if the GraphicsConfiguration's Buffer and Image Capabilitiessay that they're accelerated (see GraphicsConfiguration.getImageCapabilities()).

But this one will also return true if the older DirectDraw pipeline is enabled..

Quote

In Milpa (using PulpCore, which uses regular repaint() requests on Windows, and runs at 60fps), I noticed a few dropped frames, but not many. Oddly, I noticed occasional "half-frame" updates - the left side of the applet would occasionally be one frame ahead of the right side. This is on a Mobility Radeon 9600.

Yes, this is likely the same screen update issue. If the application just renders directly tothe screen (not even using a back-buffer), there is no way for us to tell when it's a good time to flip the fake screen surface.

Doing animations without a back-buffer - directly to the screen - is typically not a good idea.

Anyway, we might want to decrease the update thread sleep to 50ms - that shouldimprove the situation somewhat.

But the real fix is to use BufferStrategy going forward..

Quote

When I use -Dsun.java2d.d3d=false, the problem goes away. Without a doubt, the animation looks a lot better with the flag set to false.

What I mean is, is there a way to programmatically detect, at runtime, if the D3D9 pipeline is used?

If so, for existing games, at runtime the engine can use new code (using BufferStrategy) on the D3D9 pipeline, but stick with the old code (repaint()) on other pipelines (which I know already works fine on Java 1.4, Java 1.5, and the current Java 6 on Windows, on a wide variety of hardware).

Because if I had to switch to using new rendering code for all Java VMs, that creates a lot of QA work. So right now I only want to switch to new rendering code if the user has the D3D9 pipeline. (The alternative is to "guess" the VM is using D3D9 by checking if the version number is 1.6.0_05 - hairy stuff.)

Yes, relying on java version stuff would not be a good idea, for sure.Sorry, I don't have an answer for you.

We'll try to tweak the on-screen rendering so that the effect is less noticeable, but unfortunately there's just no way to make it work otherwise - short ofdisabling all attempts to accelerate on-screen rendering (or the image back-buffer to the screen scenario).

Quote

BTW, I'm really bummed about non-accelerated Xor rendering

I understand. Say 'thanks' to the dudes who designed Direct3D =)We'll try to work out something, but so far it doesn't look good.

As a workaround we may disable accelerated rendering for surfaces where xor rendering isdetected. The current approach is so slow that it's not really usable anyway.

That is what I'm talking about, improved double buffering and Thread-safe buffer management (where (Image).flush() must be handled with caution (!)). The latter of these concepts is left to your own to implement or not.

Flush() is really to be used only when you think you're done with the image.Like if you're loading a new level, old sprite images can be flushed to speed upvram recovery.

Hi Dmitri, why does this update thread only wake up every 100ms? That only 10FPS. Of course I'm sure that you've investigated, but why do we need this intermediating update thread for D3D, we didn't have it in the old pipeline and I assume that non-java D3D apps don't have it.

Thanks,Keith

Because like I said, there is no way in Direct3D 9 to render directly to the screen.You can not copy images to the screen either.

But we thought that most active rendering games at least use some kind of back-buffer (the thought was that it would typically be a VolatileImage).So we have a special case for when application copies a VI to the screen(which is redirected to our back-buffer surface) - the update thread is waken up immediately so if you use a VI as your back-buffer you shouldnot see much of a difference (well, we still do one extra step - flip theback-buffer surface).

We can make the same optimization for copying BufferedImages to thescreen - I guess many people still use BufferedImages for their back-buffers.Please let me know if this is a good idea.

Of course, no native d3d applications have this issue, because none of themrender to the screen. The way all d3d applications work is that they renderto a SwapChain (which is similar to BufferStrategy) and when they'redone with the frame, they Present() it (analog of BufferStrategy.show()).

Well, we can not introduce a new API in an update release, so that's out until jdk7.

I could easily make all BufferStrategies vsync-ed (including our "fake onscreen" one) - right now they're v-synced only in full-screen mode. But that would really mess up applications which don't expect to be throttled.

To sum it up: it looks like we'll need to do some tweaking to our on-screen rendering.

First, we'll probably decrease the update thread sleep time to 50ms, and second, wake up the update thread immediately (and wait synchronouslywhile it flips the surface) after any drawImage to the screen - it currentlyonly does this if a VolatileImage is copied to the screen.

Well, we can not introduce a new API in an update release, so that's out until jdk7.

I could easily make all BufferStrategies vsync-ed (including our "fake onscreen" one) - right now they're v-synced only in full-screen mode. But that would really mess up applications which don't expect to be throttled.

You mean, for when a BufferedImage is copied to the screeen? OK. sounds good.

Quote

By the way, is this checking thread the thread in the Single Threaded Rendering (STR)? How come the OGL pipeline doesn't need do the 100ms wake-up?

It's not, actually - the "screen updater thread" is a separate thread from the STRthread - which is the Toolkit thead in the D3D pipeline (we have to use toolkitthread because of the requirement that some Direct3D operations must bedone on this thread).

The OGL pipeline's STR thread flushes the rendering queueevery 100ms or when a VI->screen copy is detected.

One of the differences is that the operations are 'replayed' whenthe queue is flushed in the same order they were done - as opposed to the D3D case where we may flip the buffer half-way through the frame - as some folks noticed.

Quote

Fair enough. What about another J2D option sun.java2d.vsync=True?!

We're trying to avoid adding more flags. Also, the flag won't help applets and webstart apps (unless we make it public andadd to the list of 'secured' flags)

Is there really no way of fixing such things? Imagine all the old applets relying on some Java2D specifics (may be intentional or not), I am just afraid of all the "it worked, but now doesn't" publicity on javalobby et al. No dirty tricks inside the new pipeline which could make things like this work?The delay-shortening and the flush-on-all-drawImage calls seems to be a good tradeof

By the way, are even small XOR-areas a problem, I am using a non-swing toolkit for compatibility with Java-1.1 which uses XOR showing selected areas.

Is there really no way of fixing such things? Imagine all the old applets relying on some Java2D specifics (may be intentional or not), I am just afraid of all the "it worked, but now doesn't" publicity on javalobby et al. No dirty tricks inside the new pipeline which could make things like this work?The delay-shortening and the flush-on-all-drawImage calls seems to be a good tradeof

As I mentioned, Toolkit.sync() will cause a flush.

We understand that there will be incompatibilities. We'll try to address themif we can. But it's really hard to have it both ways: use modern nativeAPIs to accelerate some ancient approaches. Somebody will alwaysbe disappointed.

Quote

By the way, are even small XOR-areas a problem, I am using a non-swing toolkit for compatibility with Java-1.1 which uses XOR showing selected areas:

It really depends on the area. Currently we just do it pixel by pixel.The more pixels to cover the slower it will be.

We understand that there will be incompatibilities. We'll try to address themif we can. But it's really hard to have it both ways: use modern nativeAPIs to accelerate some ancient approaches. Somebody will alwaysbe disappointed.

Well of course I understand predicament, and I really appreciate the efforts by Sun to keep Java a alive platform on the desktop.That said, I guess it has never been more alive than now ... great Job done over the past few years. Thanks for such a great platform!

However on the other point of view I see bytecode-transformers for fixing broken bytecodes from old 1.0 and 1.1 days in the Applet-Plugin and a really great effort to stay compatible (which is what makes Sun _better_ than all those opensource runtimes in my opinion).I don't know how the compatibility-tests went that were done internally at Sun, but wouldn't it e.g be possible to make a descision which pipeline should be used depending on the bytecode-target version, maybe with a warning in the Java-Console like "Java2D compatibility pipeline enabled".I can't imagine <= Java-1.3 applets depend on Java2d performance a lot. Ok, I agree this is not elegant either - it seems it can't solved easily.

I'll see if that makes a difference. Maybe Image.flush() should wake up the update thread too?Really I should convert this code to a more modern approach; the applet was like a quick hack and the MemoryImageSource was something I had done before.

Quote

We understand that there will be incompatibilities. We'll try to address themif we can. But it's really hard to have it both ways: use modern nativeAPIs to accelerate some ancient approaches. Somebody will alwaysbe disappointed.

I can appreciate these things might cause incompatibilites. I guess it's time to deprecate ImageProducer, MemoryImageSource and friends? If they're not deprecated, I think it's really important that they will keep working as intended. My vote would go to deprecating them.

I'll see if that makes a difference. Maybe Image.flush() should wake up the update thread too?

I doubt that it would make that much of a difference, butImage.flush() is intended for releasing the resources associated with the image -as per the documentation. In 1.1 it would drop the cached pixels so that the nexttime you call drawImage ImageConsumer would get the new pixels from theproducer.

So in some way it does achieve what you wanted, but not in a really efficient waysince on every flush it drops all cached buffers instead of just updatingthem, etc.

For the "new" image types (BI, VI) - flush() releases vram resourcesassociated with the image - so if you get into a habit of calling flush()you'd get some surprises =)

Anyway, what I'm trying to say is that I don't think flush() shouldin any way affect the update thread.

Quote

Really I should convert this code to a more modern approach; the applet was like a quick hack and the MemoryImageSource was something I had done before.

I can appreciate these things might cause incompatibilites. I guess it's time to deprecate ImageProducer, MemoryImageSource and friends? If they're not deprecated, I think it's really important that they will keep working as intended. My vote would go to deprecating them.

Here's a reply on deprecation from Java2D's Jim Graham:

Quote

With regards to deprecation - deprecation was common back in the earlydays of 1.1 and even 1.2 when it was new - all APIs that weren't the"latest greatest" were deprecated, but it got to a point wheredeprecation didn't really mean much any more. The general philosophythese days is to deprecate something only if there are specific problemsassociated with its use that cannot be worked around.

So we would definitely make sure this stuff works, but not necessarilyin the best way possible - that would require too much effort..

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org