Welcome, Guest. Please login or register.

Author Topic: Warp3d synchro/double-triply bufferging  (Read 18661 times)

Description:

0 Members and 1 Guest are viewing this topic.

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Warp3d synchro/double-triply bufferging
« on: February 11, 2005, 12:44:53 AM »
First of all, stick with the ScreenBuffer based buffering. It's much less of a pain in the rear than the scrolling one IMHO.

Secondly use WaitBOVP(&(screen->ViewPort)) to wait for the buffer flip. I have found this works a lot better than WaitTOF().

Thirdly, when you change buffers, remember to update your W3D_Context to use the newly released buffer for rendering using W3D_SetDrawRegion(), otherwise you will be still rendering to the same BitMap that before the buffer flip was the invisible one but now is the visible one.
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Warp3d synchro/double-triply bufferging
« Reply #1 on: February 11, 2005, 02:01:53 AM »
You don't have to use the ScreenBuffer approach, I just find it works better than the tall screen / ScrollVPort method.

Right, about double (or triple) buffering in general. The basic idea is that you always draw to a BitMap that is currently invisible. Once the drawing is done, you swap this BitMap for the one currently on display (waiting for the appropriate synchronization). The BitMap you just drew on is now on screen and the one that was on screen is now available to draw on.

Doing this ensures that you never "see" the rendering happening, which would otherwise produce a very flickery image.

A consequence of this is that the "invisible" and "visible" BitMaps keep swapping over.

Therefore, regarding the W3D_SetDrawRegion() call, you have to do this every time you flip the buffers, not just when you first set up the context. From the looks of what you have written, this is the thing you are neglecting.

So every time you do the ChangeScreenBuffer(), you must also do W3D_SetDrawRegion() to tell the W3D_Context to use the "current" invisible BitMap.

One problem I noticed with your code is that you call the AllocScreenBuffer() both times using the SB_SCREEN_BITMAP argument. This arguement is used to associate the existing screen's BitMap with the ScreenBuffer, not allocate a new one. So in your case you never really had a second buffer anyway, they were both simply pointers to the screens's one. You dont use the SB_SCREEN_BITMAP when you want to actually create an invisible buffer.

Another thing to consider is that the ChangeScreenBuffer() call can fail at the point you call it. An ugly (but working) way around this is to do something like this

Screen* screen;
W3D_Scissor scissor { ... };
ScreenBuffer* buffer[2];
int drawBuffer;

//...

// create the initial visible buffer (this is just the screens bitmap)
buffer[0] = AllocScreenBuffer(screen, NULL, SB_SCREEN_BITMAP); // doesn't allcoate BitMap

// create the initial invisible buffer. Note the second argument is 0
buffer[1] = AllocScreenBuffer(screen, NULL, 0); // does allocate BitMap

// the second buffer is the initial drawing buffer
drawBuffer = 1;

// function to swap the buffers
void mySwapBuffer()
{

// make sure we swap the buffer. This truly is an ugly way, but it works - in any case, the busy loop is almost always never entered. But for the love of god don't do anything like this in a WarpOS ppc version - possible frenzy of context switches - make it a 68K function .

buffer[drawBuffer]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort=0;
while (!ChangeScreenBuffer(screen, buffer[drawBuffer]))
  ;

// change the drawBuffer number
drawBuffer ^= 1;

// wait for bottom of viewport sync
WaitBOVP(&(screen)->ViewPort);

// update the context to use the new draw region
W3D_SetDrawRegion(context, buffer[drawBuffer]->sb_BitMap, &scissor);

}


If you use the above function (or similar - this is from memory), you should experience smooth, unflickering graphics.

Forget all about the YOffset thing, just use 0. It's only needed for the ScrollVPort() buffering strategy anyway.
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Warp3d synchro/double-triply bufferging
« Reply #2 on: February 11, 2005, 02:43:10 AM »
Oh, a note about triple buffering...

Double buffering is your primary means of eliminating flicker by ensuring the rendering is done off screen. However, the synchronization step involved in switching the buffers can cause a stall.

Suppose you *just* miss the next monitor frame - you end up waiting for the next one after that before you can proceed to render.

Triple buffering mitigates this by using a queue of three buffers rather than a pair. This way you always have a buffer ready to render into on every monitor frame.

For systems with faster CPUs (ie capable of faster rendering), this can produce a smoother experience.
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Warp3d synchro/double-triply bufferging
« Reply #3 on: February 11, 2005, 05:50:17 PM »
@kas1e

If you want to send me your code/binary I don't mind having a quick look. I'll pmail you my email address.

I use double/triple buffered ScreenBuffers on my BPPC 68040/25 + BVision without any great problems. One of the things is knowing exactly where to put the WaitBOVP() call - it can make all the difference.

You don't need to use a ScreenBuffer for the ScrollVPort() method, it's only for the ChangeScreenBuffer() version.
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Warp3d synchro/double-triply bufferging
« Reply #4 on: February 16, 2005, 10:29:07 PM »
Quote

RWO wrote:
Karlos do you know how to do window double buffering?

-RWO


Piru is right in that there is no such thing. However, if you AllocBitmap() a BitMap using the display's BitMap as a friend, you will create an offscreen buffer you can render to.

You then use a call such as ClipBlit() to blit the offscreen buffer to the window. It isn't as fast as fullscreen (the blit actually does take some measurable time on older cards), but you achieve desired effect.
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Warp3d synchro/double-triply bufferging
« Reply #5 on: February 16, 2005, 10:32:07 PM »
Quote

EntilZha wrote:
Quote
Yes it is. It should use the buffering provided by the ScreenBuffers. With ScreenBuffer it would be perfectly synched to the display beam, and it would never busyloop.


It does use ScreenBuffers.

Quote
Also, the code does some nasty manual busylooping if the ScreenBuffer cannot be swapped instead of just refusing the swap (ok, there might be some implementation specific reasons why it MUST always succeed to swap). Such while loops can create nasty lockup. If construct like this MUST be used, the code should sleep a bit after each failure.


It hardly ever fails to swap the screen buffer, anyway.



I ran a piece of code for two hours solid when testing something. In that time, the ChangeScreenBuffer() never failed once. I was curious to see if the while(!ChangeScreenBuffer(...)); call busy looped so had it increment a counter. It was still zero after the strain test finished.

I'd say Thomas remark here was understated even.
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Warp3d synchro/double-triply bufferging
« Reply #6 on: February 17, 2005, 03:59:52 PM »
Quote

Mr_Capehill wrote:
Karlos, does it make a big difference speed wisely to have a friend bitmap? I usually just allocate a bitmap with certain colour format properties and use BlitBitMapRastPort(), letting the OS handle all kind of conversion and saving me the trouble to support various possible colour formats.


It does indeed make a difference. Depending on your RTG card/driver, you might find that your graphics are converted by software.

I benchmarked the OS conversion and discovered that all cross-format blits on my CGX/Permedia2 were done in software by the driver software and not particularly quickly either. As a consequence I wrote my own routines and a 2D function LUT to do the job. These were hand optimised asm that did each possible conversion (there are less than 14x14 - most conversions are symmetrical) as fast as possible, taking advantage of 32-bit accesses, rotate instructions etc not available at the C level. They outperformed the OS blit routines by up to 3x on my system depending on the source/destination formats.

Anybody who ever ran my pixeltest tool has inadvertendly seen these routines, pixeltest was actually written purely to benchmark them (unbeknown to the users at large, you can specify the source data format on the command line).

Bottom line is:

Allocate your offscreen BitMap as a friend of the display. This ensures

a) that the BitMap is in Video memory

b) that the BitMap in the same format as the display, meaning that any Blit will be done in HW.

For Warp3D's hardware acceleration to work, (a) is absolutely essential anyway.

The downside is that you will have to care about the supported formats yourself. However, you would be very unlucky to encounter anything other than the following hardware formats

8-bit CLUT
15-bit RGB big endian (A1:R5:G5:B5)
15-bit RGB little endian
16-bit RGB big endian (A0:R5:G6:B5)
16-bit RGB little endian
32-bit ARGB
32-bit BGRA (just 'little endian' ARGB32 ;-) )

which is a lot less than the total possible number of formats supported.

Even 24-bit packed pixel modes are rare on any half modern graphics card.

Only rely on the OS to do the conversion if speed is not essential to your application. Or at least allow the user to choose (I envisage newer drivers that properly do colourspace conversion in hardware will appear)
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Warp3d synchro/double-triply bufferging
« Reply #7 on: February 17, 2005, 08:13:17 PM »
@Mr_Capehill

Sure, but it is obscenely boring to watch :lol:

I'll put a version up in a moment (and edit this post when done).

-edit-

I lied, I posted a new post. Oh wait, no I didn't, this is an edit....

/me crashes in an infinite loop...
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Warp3d synchro/double-triply bufferging
« Reply #8 on: February 17, 2005, 09:00:39 PM »
You can find pixeltest here
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Warp3d synchro/double-triply bufferging
« Reply #9 on: February 18, 2005, 12:04:56 PM »
@Framiga

Hehe, glad you like it. It sort of is public, just not on aminet :-)

Note: epending on your 3D driver and wether or not I compiled the gfxlib of the framework to use the warp3d v3 functions for lines, the "show mesh" option might not work at all.

So, let's see your picture then :-D
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Warp3d synchro/double-triply bufferging
« Reply #10 on: February 18, 2005, 12:16:32 PM »
If I weren't so lazy, I'd add the options to save the images and deformations directly.

I sort of had the idea of literally allowing you to save any particular deformation as a keyframe to a file that could then be used to make animations and so on.

However, it was actually written as a sort of fun way to estimate texture fill rates more than anything (I took that code out of it before making it a toy) and so on.

If you look at the source code (which should be included, but you need the framework to build it), you can see it isn't something I really lavished too much effort on ;-)
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Warp3d synchro/double-triply bufferging
« Reply #11 on: February 18, 2005, 12:29:25 PM »
Quote

Framiga wrote:

EDIT- about the mesh, should it be a sort of grid?



The 'show mesh' option should show a line grid on top of the basic image, which is then dimmed slightly, showing you where the vertices are.

However, I think the current build of the gfxlib part of the framework was compiled using *only* warp3d vertex array methods.
 
It so happens that for 680x0/OS3.x, only an unreleased (experimental) permedia2 actually supports all the warp3d v4 drawing methods. I know the 4.2 driver and the equivalent voodoo drivers certianly don't do it.

In the gfxlib / Rasterizer class, there is a compiler switch to render points and lines using the V3 methods because of this, but it was switched off here I think.
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Warp3d synchro/double-triply bufferging
« Reply #12 on: February 18, 2005, 12:31:59 PM »
Quote

Framiga wrote:

btw . . . Warpdemo accepts only 256x256 pics?



In theory, any power of 2 * any other power of 2. Basically the texture limiations of warp3d itself apply.

If you are stuck on 256x256, I bet you have a voodoo :-D

I got a 512x512 one working on my permedia2 no problem ;-)
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Warp3d synchro/double-triply bufferging
« Reply #13 on: February 18, 2005, 12:34:33 PM »
Quote

Framiga wrote:

About looking inside the source . .  . Karlos do you wanna kill me :-)


Nope. Why, is it that bad? A few things you probably noticed

1) there is no main() function.
2) the program is a C++ class
3) there isn't a single line of AmigaOS specific code anywhere ;-)


Quote
Its chinese for me :-(


Try a tab space of 2 - that's what I use. It will make it look a lot tidier at least :-)
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Warp3d synchro/double-triply bufferging
« Reply #14 on: February 18, 2005, 12:48:58 PM »
BTW, anything written with my framework supports a "-sysdebug" option on the CLI which can be handy when stuff doesnt work that maybe isn't the application's fault.
int p; // A