design question

I’m using Pbuffers to simulate various Graphics2D functions.

Of course I cannot determine when a given graphic operation takes place, so I cannot use the Display() to draw my graphics.

Imagine this:
myGLGraphics.drawRect(10,10,100,100);

The drawRect should get the current Pbuffer GL context and execute the required GL commands. No, it doesn’t work.

I tried to cache the GL pointer with no success (even more it is not advisable to do this in jogl).

Maybe I should make a pbuffer context current from outside the Display() method. But how ?

Fundamentally you need to pass information about the drawRect call into your GLEventListener for the pbuffer. Imagine an implementation like this:


public class MyGLGraphics {
  private MyGLEventListener myListener;
  public void drawRect(int x, int y, int w, int h) {
    DrawRectCommand draw = new DrawRectCommand(x, y, w, h);
    synchronized (myListener) {
      myListener.serCurrentCommand(draw);
      myPbuffer.display();
    }
  }
  ...
}

public class MyGLEventListener implements GLEventListener {
  public void setCurrentCommand(Command command) {
    this.command = command;
  }
  public void display(GLDrawable drawable) {
    GL gl = drawable.getGL();
    synchronized (this) {
      if (command != null) {
        command.execute(gl);
        command = null;
      }
    }
  }
}

This would cause the primitive to be drawn immediately.

You could also think about buffering up commands and sending them down to the pbuffer in one shot. Sun’s implementation of the Java2D pipeline is either doing this already or beginning to do it.

You should also consider putting a producer/consumer queue between your MyGLGraphics code and the GLEventListener, and doing all of the rendering to the GLEventListener from another thread which has called setRenderingThread(true) on the GLPbuffer. This will cause all of the OpenGL work to be done on a single thread, which is more robust on many vendors’ graphics cards and, from what I hear from the Java2D team, also much faster than making OpenGL contexts current on multiple threads.

You are the greatest!
Many thanks for the suggestions. I’ve already implemented something based on your sample code and it works very well.
I would go further with the commands queue. Let’s see…

Can you estimate the additional memory/speed overhead of creating a new class for each graphical command ?

Very low but it will tax the GC unless tuned correctly. I know you’re doing realtime video stuff, am I right? In which case unexpectedly dropping frames because of GC might not be so good :confused:

Cas :slight_smile:

I use a stream of pre-calculated buffers (from 4 to 100) so that GC would not hit that much.

Suggestions welcome however!

I’ve heard that the Sun Java2D team is using a direct ByteBuffer to send tokens between the producer of the graphical commands and the consumer thread doing the rendering, rather than allocating a new Command object each time. You might want to consider a similar strategy.

However, young-generation scavenges are very fast (on the order of 1 millisecond or less), and if you’re producing garbage that is short-lived then you may not see any problems. Premature optimization is the root of all evil.

[quote]Premature optimization is the root of all evil.
[/quote]
Aha, you’re so right!
I did some similar approach by using arrays and it worked, but I prefer the command way. The classes are anonymous and short lived. From the performance side, there are no visible differences from the direct method invocation.

Anyway I didn’t use a producer/consumer pattern.
I created a Master class that creates a thread that waits for commands. The commands are created inside the Master itself through anonymous inner classes. The calls are synchronized through a lock, so I can wait for a reply from the call (useful for pbuffers/textures allocation inside the thread).

some snippets:

the SGLBitmap allocation


      public SGLBitmap newSGLBitmap(final int width, final int height, final int samples)
      {
            return (SGLBitmap) invokeCommand(new SGLCommand()
            {
                  public Object execute()
                  {
                        return new SGLBitmap(width, height, samples);
                  }
            });
      }

The drawImage


      public void drawImage(final SGLContext ctx, final SGLImage img, final float x, final float y)
      {
            invokeCommand(new SGLCommand()
            {
                  public Object execute()
                  {
                        ctx.drawImage(img, x, y);
                        return null;
                  }
            });
      }

the invokeCommand


      // call a command in the thread
      private Object invokeCommand(SGLCommand cmd)
      {
            synchronized (lock)
            {
                  sendCommand(cmd);
                  return waitReply();
            }
      }

the server


      // the server code
      public void run()
      {
            synchronized (lock)
            {
                  while (true)
                  {
                        sendReply(waitCommand().execute());
                  }
            }
      }

I would like to avoid to run in a synchronized block, but I didn’t find a reliable solution.

You didn’t show how waitReply() works but assuming that you are using wait()/notify() on the client and server sides that’s probably pretty efficient. If you really wanted to, on multi-CPU machines you might consider spinning for a while instead of waiting, and/or using a lock-free queue like java.util.concurrent.ConcurrentLinkedQueue (new in 1.5).