Please try the new Direct3D 9 pipeline in 6uN EA

Hello,

Sun had released an Early Access of 6uN (formerly known as
the Consumer Release). You can get b04 here:
http://download.java.net/jdk6/

This build contains the new Direct3D 9-based Java2D pipeline,
which is enabled by default on Windows platform. It is very similar to the
OpenGL pipeline (in fact they share a lot of code), and is
based on Single Thread Rendering model developed for the OpenGL
pipeline (http://weblogs.java.net/blog/campbell/archive/2005/03/strcrazy_improv_1.html)

The D3D pipeline accelerates pretty much the same set of operations
as the OGL one as well:
http://weblogs.java.net/blog/campbell/archive/2004/11/behind_the_grap.html

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.

Please report both negative and positive findings…

Take a look at this page for testing/troubleshooting guidelines:
https://jdk6.dev.java.net/testD3D.html
You can report issues either on this forum, or on this one
(which is linked to the java2d-interest mailing list):
http://forums.java.net/jive/forum.jspa?forumID=69

There are some known problems in full-screen mode, multi-screen,
and on some chipsets (namely, Intel 645G). These are being worked on
and hopefully will be addressed by the release time.

Another thing to be aware of - this pipeline does not
accelerate Xor rendering mode. It will be really, really slow.
Sorry about that.

Thanks,
Dmitri
Java2D Team

I’m seeing something really strange in JEmu2 after installing this java version.
If I run the applet at http://www.gagaplay.com/jemu2/applet/applet.php?w=640&h=448&driver=outrun with the D3D pipeline enabled, it doesn’t draw all frames anymore. It simply skips a lot of frames, resulting in a very choppy display. This doesn’t happen using the OpenGL pipeline.

Maybe it is somehow related to how the applet does the rendering:

  • The init() method starts a new Thread.
  • In the thread, there’s a loop which simply does the following:
     emu.refresh(true); // update the emulator for 1 frame, updating the int[] which is backing the backBuffer Image
                backBuffer.flush();
                g.drawImage(backBuffer, (width - (emuWidth * scale)) / 2, (height - (emuHeight * scale)) / 2, emuWidth * scale, emuHeight * scale, null);
                throttle(); // slow down to the correct framerate using Thread.sleep()

I have an Intel Mobile 945GM Express.
I’ll see if I can make a small test case.

I hope this helps.

Thanks Erik.

May I ask why do you do backBuffer.flush() before the drawImage?

Is backBuffer a VolatileImage or a BufferedImage?

One issue may be that since it is not possible to render directly to
the screen in Direct3D9 we have this emulated mode where
we redirect all on-screen rendering to an off-screen ‘buffer strategy-like thingie’
which is then flipped by another thread once in a while. Normally
the update thread wakes up every 100ms, unless you copy a
VolatileImage to the screen, in which case we take it as a
clue 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 instead
of 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 =)

Thanks,
Dmitri

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. :wink:

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.

I’ll try BufferStrategy later to see if there is any difference.

Like the opengl pipeline, if you use big T True then it seems to print to standard out if the pipeline is working or not, so try:
-Dsun.java2d.d3d=True

By the way Dmitri, is there any progress on this issue with this bug:
http://www.java-gaming.org/forums/index.php?topic=14696.0
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6378181

The Direct3D pipeline is a great addition by the way! 8) It’s pretty exciting

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 :

/***/
    Thread screen = null;
    
    /** returns screen refreshing task
     * @return screen refreshing task*/
    protected ActionListener getScreenTask() {
        return new ActionListener() {
            
            public void actionPerformed(ActionEvent pe) {
                final ActionEvent e = pe;
                if (screen instanceof Thread) {
                    if (screen.isAlive()) {
                        return;
                    }
                }
                Thread t = screen = new Thread(vSynch, new Runnable() {
                    
                    public void run() {
                        if (!isDisplayable()) {
                            return;
                        }
                        if (bufferSynch == null) {
                            return;
                        }
                        boolean interrupt_ = false;
                        setIgnoreRepaint(activeRendering);
                        if (activeRendering) {
                            final CoalescedThreadsMonitor monitor0 = bufferSynch;
                            synchronized (monitor0.getMonitor(true)) {
                                monitor0.notifyOnMonitor();
                                if (buffering) {
                                    System.err.println("RenderingScene screen task is waitin' for buffering...");
                                }
                                while (buffering) {
                                    System.err.print(".");
                                    try {
                                        monitor0.waitOnMonitor();
                                    } catch (InterruptedException ex) {
                                        ex.printStackTrace();
                                        Thread.currentThread().interrupt();
                                    }
                                }
                                try {
                                    rendering = true;
                                    doBeforeScreenTasks(e);
                                    System.out.println(((activeRendering) ? "-HARD RENDERING-" : "-SOFT RENDERING-") + "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\screen initied - " + System.currentTimeMillis());
                                    BufferStrategy strategy = RenderingScene.this.getBufferStrategy();
                                    Graphics g = null;
                                    do {
                                        do {
                                            g = strategy.getDrawGraphics();
                                            if (g != null) {
                                                Rectangle box = new Rectangle(0, 0, getWidth(), getWidth());
                                                g.setClip(box);
                                                g.clearRect(box.x, box.y, box.width, box.height);
                                                draw(g, RenderingScene.this);
                                                g.dispose();
                                            }
                                        } while (strategy.contentsRestored());
                                        if (isDisplayable()) {
                                            strategy.show();
                                        }
                                    } while (strategy.contentsLost());
                                    doAfterScreenTasks(e);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                    interrupt_ = true;
                                } finally {
                                    rendering = false;
                                }
                            }
                            final CoalescedThreadsMonitor monitor1 = vSynch;
                            synchronized (monitor1.getMonitor(false)) {
                                monitor1.notifyAllOnMonitor();
                            }
                            if (interrupt_) {
                                Thread.currentThread().interrupt();
                            }
                        } else {
                            repaint();
                        }
                    }
                }, "T-screen-refresh");
                t.setPriority(Thread.MAX_PRIORITY);
                t.setDaemon(false);
                t.start();
            }
        };
    }

The actionListener is then sent to a Swing Timer that makes the event occur every 10ms if possible or skip.

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.)

BTW, I’m really bummed about non-accelerated Xor rendering ;D

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?

Maybe this will work (I don’t have a jdk on this computer to make sure): System.getProperty(“Dsun.java2d.d3d”);

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

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 :wink:

Unfortunately there isn’t. As of now the sun.java2d.d3d property is set to ‘true’ by default
and 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 Capabilities
say that they’re accelerated (see GraphicsConfiguration.getImageCapabilities()).

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

Yes, this is likely the same screen update issue. If the application just renders directly to
the 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 should
improve the situation somewhat.

But the real fix is to use BufferStrategy going forward…

Please let us know how it goes.

Thanks,
Dmitri

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 of
disabling all attempts to accelerate on-screen rendering (or
the image back-buffer to the screen scenario).

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 is
detected. The current approach is so slow that it’s not really usable anyway.

Thanks,
Dmitri

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 up
vram recovery.

I can not think of why one would flush the back-buffer, though.

Dmitri

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 should
not see much of a difference (well, we still do one extra step - flip the
back-buffer surface).

We can make the same optimization for copying BufferedImages to the
screen - 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 them
render to the screen. The way all d3d applications work is that they render
to a SwapChain (which is similar to BufferStrategy) and when they’re
done with the frame, they Present() it (analog of BufferStrategy.show()).

Thanks,
Dmitri

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.

Thanks,
Dmitri

I don’t get it. This is the consumer JRE (or what used to be known as is). One of the features
is this accelerated pipeline.

I do agree though that it is dangerous to introduce such a change (a new default
rendering pipeline) in what is supposedly just an update release.

Oh, the dreams, the dreams =)

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 synchronously
while it flips the surface) after any drawImage to the screen - it currently
only does this if a VolatileImage is copied to the screen.

What do you think?

Thanks,
Dmitri

Great, yes immediate wake-up is needed. 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?

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

Thanks for the quick response and great work with the pipeline!

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

It’s not, actually - the “screen updater thread” is a separate thread from the STR
thread - which is the Toolkit thead in the D3D pipeline (we have to use toolkit
thread because of the requirement that some Direct3D operations must be
done on this thread).

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

One of the differences is that the operations are ‘replayed’ when
the 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.

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

Thanks,
Dmitri