createBufferStrategy(n>2), chain access?

Hi everyone,

somehow I don’t get it: If I use a BufferStrategy with more than 2 Buffers how do I get an instance of Graphics for the backbuffers other than the one that will be displayed next.

Say we got 4 buffers. Buffer 0 is being showed, Buffer 1 has been done and now I want to render on Buffer 2 but I don’t want to show buffer 1 already because I want a constant framerate of 30. (grr 3x want :-X )

If that’s not possible what is the sense of more than 3 buffers?
living in the past -> use 1 buffer :stuck_out_tongue:
no tearing -> use 2 buffers
no wait for vsync -> use 3 buffers

4 and more buffers would behave the same as 3 buffers (not?)

My basic intention:

Assume we are using n buffers. There are n-1 buffers left for “prerendering”. If I have a constant fps=30 my rendercode has to be able to render n-1 frames in the time (1s/30)*(n-1) which ist not the same limitation as 1 frame in the time (1s/30) because one of these n-1 frames could have been a bit more complex and another one less: 3/60 seconds+1/60 second = 4/60=2/30 seconds. In this example though one took too long both together didn’t take too long -> smooth fps. (If we are lucky.)

See what I mean? Or see what I miss ???

I read the following: http://java.sun.com/docs/books/tutorial/extra/fullscreen/example-1dot4/MultiBufferTest.java

They say it’s a “MultiBufferTest”?! I don’t think that it tests multiple buffers. Their render loop:


            BufferStrategy bufferStrategy = mainFrame.getBufferStrategy();
            for (float lag = 2000.0f; lag > 0.00000006f; lag = lag / 1.33f) {
                for (int i = 0; i < numBuffers; i++) {
                    Graphics g = bufferStrategy.getDrawGraphics();
                    if (!bufferStrategy.contentsLost()) {
                        g.setColor(COLORS[i]);
                        g.fillRect(0,0,bounds.width, bounds.height);
                        bufferStrategy.show();
                        g.dispose();
                    }
                    try {
                        Thread.sleep((int)lag);
                    } catch (InterruptedException e) {}
                }
            }

This code changes the color on the screen always the same way no matter how many buffers it really uses?! Doesn’t it?
It could check the existence of n buffers if it did only color every buffer once and than never again. But still loop through bufferStrategy.show().

I am not sure wether I’d know what I am asking if it weren’t myself ;D

LastBoyScout

You are only supposed to care about the next buffer in the chain. Note that with more than 2 buffers this may NOT be the buffer that will be displayed next, it will be the buffer that is displayed after the last one you got - which isn’t necessarily the one that is displaying now.

The point of more buffering is always the same… to smooth out the flow of information and keep things working efficiently.

If you were using a buffer strategy to show an animation file (MPEG/AVI,etc) and your I/O to that file was a bit unsteady… having more buffering would allow you to have a few frames ready for times when it takes to long to draw the next frame in the file. in this case as the display ‘flips’ it will use up the buffers that are waiting to be displayed giving you a bit more time to get a new frame drawn.

More buffers means potentially higher lag between your drawing and displaying - but sometimes that is easier to deal with than not being able to keep up with drawing at a constant rate.

So yes the behavior of 4 buffers is the same as 3… but it gives you resistance to longer lags in your rendering code.

Hey swpalmer,

hmm okay I know that. I don’t really want to have direct “random access” to every buffer.

But how do I get the next buffer when I finished one buffer?
Doesn’t .getDrawGraphics() always give the instance of Graphics belonging to the next buffer to display?
Or do I get the “overnext” buffer if i call .getDrawGraphics() a second time?

Say we got 4 buffers0 to 3. Buffer0 is being showed. Now I call .getDrawGraphics() and get Graphics for Buffer1. I render this frame and .dipose() the Graphics. Now I call again .getDrawGraphics() (didn’t call .show() yet!). What do I get now? Buffer1 or Buffer2?

And what happens if buffer0 is being showed and buffer1 to 3 are rendered and I call .getDrawGraphics(). Will it block 'till there’s a free buffer ('till someone calls .show()) or Excpetion or what?

thx

I’m almost positive you then get buffer2. You’d have to, anything else doesn’t make sense and goes against the whole purpose of >2 buffering. This whole thing is quite the black box, so I don’t think we can easily find out for certain. But BufferStrategy should know how to optimally run itself based on how you set it up.

My guess would be it’d block. But if you’re filling 3 buffers in 1/60th of a second, I’d worry about what to do with all that extra processing power you’re wasting :slight_smile:

HELL,

seems like BufferStrategy is a blacker box than you/we thought!

Check this short test:


            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
            GraphicsDevice gd = ge.getScreenDevices()[0];

            GraphicsConfiguration gconf= gd.getDefaultConfiguration();

            Frame frame = new Frame(gconf);
            frame.setLayout(null);
            frame.setIgnoreRepaint(true);
            frame.setUndecorated(true);

            gd.setFullScreenWindow(frame);
            DisplayMode dm = new DisplayMode(800,600,32,75);
            gd.setDisplayMode(dm);

            int nBuffers = 5;
            frame.createBufferStrategy(nBuffers);
            BufferStrategy bstrat= frame.getBufferStrategy();
            
            //Buffer 0 is visible
            
            //wait for fullscreen to settle down
            try {
                  Thread.sleep(5000);
            } catch(InterruptedException e) {
                  throw new Error(e);
            }

            //prerender Buffer 1 -> blue
            Graphics g = bstrat.getDrawGraphics();
            g.setColor(Color.blue);
            g.fillRect(0,0,800,600);
            g.dispose();
            g = null;
            
            //prerender Buffer 2 (?) -> red
            g = bstrat.getDrawGraphics();
            g.setColor(Color.red);
            g.fillRect(0,0,800,300);
            g.dispose();
            g = null;
            
            //Buffer 0 has already been showed
            //now show me buffer 1,2,3 and 4 (we have 5 buffers)
            for(int i=1;i<=4;i++) {
                  //Buffer i wird angezeigt
                  bstrat.show();
                  try {
                        Thread.sleep(1000);
                  } catch(InterruptedException e) {
                        throw new Error(e);
                  }
            }
            
            frame.hide();
            frame.dispose();
            frame = null;
            
            System.exit(0);

One would expect the following: First picture we see for 5 seconds is undefined, then for 1 second we see blue, 1 second half of screen red, remaining buffers are undefined.

BUT at least on my machine I see undefined, upper half red lower half blue, remaining buffers undefined.

So those two instances of Graphics both work on buffer1. -> Question 1
Question 2 no longer “exists”.

So, as tortoise said, “the whole purpose of >2 buffering” can’t be achieved with BufferStrategy?!
Maybe n=3 helps with vSync. But >3 doesn’t change ANYTHING but memoryusage!?
Can it be?

???

Grrr I hope I made a mistake.

re-read swpalmers post.
It explains exactly the purpose of >3 buffers.

Also, to the code you posted, getDrawGraphics() will return a graphics context to the same back buffer until you call show().

It is show() that increments the back buffer counter.

Back buffers are also VolatileImages, hence they can lose their contents. You cannot fill buffer 1, blue, 2 green, 3 red, and assume that when you next come to flip them they will be in the same state you left them.

Contents undefined means exactly that, when you move to the next back buffer in the chain, its contents are undefined!
It may not be in the state you left it in previously.

Also, I would recommend thoroughly reading the documentation for the BufferStrategy class in the api docs. It does answer the question you are asking - in a round-about way :smiley:

show()
Makes the next available buffer visible by either copying the memory (blitting) or changing the display pointer (flipping).

Notice it says next available… it does not necessarily mean show the buffer that you just finished drawing to. What I don’t see and what I think is the case, is that this is the only method to advance drawing to the next buffer. (right?)

However without syncing to the vertical refresh I don’t see how more than 2 buffers can would work properly… you DON’T want the buffers to flip at the exact times that you are done rendering to them - your frame rate would have too much jitter.

In my API doc 1.4.2 I don’t see it. I think the behavior is not well explained on the API docs.

For .show() it says that it displays the next buffer in chain. Ok.

But for .getDrawGraphics() it says nothing. Just that you get “the graphics on the drawing buffer”.

There is some ascii art. First diagram shows the case with double buffering and the second diagram shows the one with triple buffering.
Both are still to special (2 buffers, 3 buffers) to guess the “general behavior”.

From these two diagrams i’d say the prerender buffer is always the last one that has been showed (not the next one to show -> but noone corrected me on this in the last posts?!). So .getDrawGraphics() depends just on .show()!??!

The API doc of BufferStrategy isn’t big enough that someone could read it not thoroughly.

Swpalmer says that I am supposed to care about the next buffer in chain. Next buffer in the sense of “what I’ve already prerendered” or in the sense of “the .show()'s”.

If the by .getDrawGraphics referenced buffer moves only with the .show()'s then it makes no sense?! Since my fps is still connected to the renderrate my app has.

I still don’t get it. Don’t I have to be able to cycle the prerender backbuffer in the chain independently from the .show()'s? Isn’t that what swpalmer would need to (in his example with the streaming movie)?

If not someone please explain me. And if it is like that: how can i do it?

PS: What you (Abuse) said about the VolatileImages and that it is a problem with my interpretation is probably true. But it’s also a problem with the triple buffering showed in the ascii art diagram in the API doc of BufferStrategy. Front buffer is being showed. You render to the back buffer. If you call .show() front buffer becomes back buffer, mid buffer becomes front buffer (is visible) and back buffer (we just rendered to) becomes mid buffer -> mid buffer will be visible as next frame… but it’s a volatile image -> could be lost -> could be lost before it is displayed.

[quote]If the by .getDrawGraphics referenced buffer moves only with the .show()'s then it makes no sense?! Since my fps is still connected to the renderrate my app has.

I still don’t get it. Don’t I have to be able to cycle the prerender backbuffer in the chain independently from the .show()'s?
[/quote]
This is where I am unsure. But as I said - I think “show()” DOES NOT SHOW if page flipping is sync’d to vertical. I think it simply advances which buffer is returned by getDrawGraphics, and queues the buffer to be shown when the vertical retrace triggers it. I don’t think it is possible to ever skip showing a buffer in the ring… they must always be displayed in order. I see no API to change to the next buffer other than what is implied by show().

This needs better documentation… because obviously with triple buffering or more when you call show() you really just want to move your rendering to the next buffer… you don’t want that buffer to be shown immediately, or even ‘next’… you want show() to queue the buffer to be shown in order.

BUT when the buffer flipping is done with a blit that is not sync’d to the monitor refresh what happens? Does show() do the blit immediately? If so you could blit through several buffers before the monitor even had a chance to draw them… How would you limit your frame rate without also artificially limiting your drawing speed, and thus ruining the purpose of having more buffers in the first place???

Someone that knows the answers please help!