Maybe somebody with deeper knowledge of Amiga OS 4.1 could help me out, please.
While following allong with the examples on http://www.kaiiv.de/retrocoding/1/ I found that the examples are extremly slow on AmigaOS 4.1. So slow infact that I could crash my X5000 by making the window larger (from 320x160 to 1920x1080).
The BltBitMapRastPort call takes a lot time if back puffer bitmap is created with AllocBitMap (the V39 call, not the tag one). Strangely, when replacing AllocBitMap with AllocBitMapTags even with the same flags, the blitting is extremly fast.
Why is that so? I did not find anything in the Autodocs that AllocBitMap is deprecated or has issues.
Here comes an example for local testing. Compile it with: gcc engine3_os4.c -lamiga -o engine3_os4
To test it, enlarge the window to cover the whole screen; drawing a 1920x1080 window takes about 2s for me.
void ComputeOutputSize(struct RenderEngineData* rd)
{
/* our output size is simply the window's size minus its borders */
rd->outputSize.x =
rd->window->Width - rd->window->BorderLeft - rd->window->BorderRight;
rd->outputSize.y =
rd->window->Height - rd->window->BorderTop - rd->window->BorderBottom;
}
void DispatchWindowMessage(struct RenderEngineData* rd,
struct IntuiMessage* msg)
{
switch(msg->Class)
{
case IDCMP_CLOSEWINDOW:
{
/* User pressed the window's close gadget: exit the main loop as
* soon as possible */
rd->run = FALSE;
break;
}
case IDCMP_NEWSIZE:
{
/* On resize we compute our new output size... */
ComputeOutputSize(rd);
/* ... and trigger a render call */
rd->doRender = TRUE;
break;
}
case IDCMP_REFRESHWINDOW:
{
IIntuition->BeginRefresh(rd->window);
/* We do only repaint here if there is no pending
* render call */
if(!rd->doRender)
{
RepaintWindow(rd);
}
if(rd->run)
{
/* let's sleep until a message from our window arrives */
IExec->Wait(winSig);
}
/* our window signaled us, so let's harvest all its messages
* in a loop... */
while((msg = IExec->GetMsg(winport)))
{
/* ...and dispatch and reply each of them */
DispatchWindowMessage(rd, (struct IntuiMessage*)msg);
IExec->ReplyMsg(msg);
}
}
I am not talking about the call itself. Yes, the AllocBitMap call might take a couple of microseconds longer than AllocBitMapTagList because the call is intercepted and then converted to a call to the newer function.
What I am seeing is that blitting the bitmap created by AllocBitMap to the window bitmap takes much, much, much longer than blitting the bitmap created by AllocBitMapTags. I am talking about a factor of 100 or so.
yah, is should be the same, but it can be that one use displayable bitmap, while the other is not. Its advised to use friend bitmap, to make it the same as other bitmap.
(NutsAboutAmiga)
Basilisk II for AmigaOS4 AmigaInputAnywhere Excalibur and other tools and apps.
IIRC the obsolete AllocBitMap() function is only working correctly if BMF_CHECKMASK is used, i.e. the "FriendBitmap" isn't a bitmap but a TagList pointer.
Of course AllocBitMap() still works without using BMF_CHECKMASK, but the result may be a planar bitmap, which is extremely slow on gfx cards.
Both calls use the same flags and the same friend bitmap. So, why should there be a difference?
I don't have any inside knowledge of how graphics.library works, so I can only make educated guesses as to what might be going on, based on the results you're seeing.
I suspect that as an OS 3.0 function, AllocBitMap() has to be backwards compatible in order to allow old OS3 programs to run, even when passed a friend BitMap. While as an OS 4.1 function, AllocBitMapTags/TagList() is free to assume a more modern program is calling it, on a more modern machine. So even when passing the same parameters, you might be getting a different BitMap depending on which function you call.
I imagine you're running the example program on a 32-bit truecolor Workbench screen, which means your friend BitMap is also 32-bit truecolor. But the backBuffer BitMap you're allocating has a depth of only one bit. So the question is, what happens when you ask for a one-bit color-mapped BitMap, but pass a 32-bit truecolor friend BitMap?
Back in the OS 3.1 days even graphics cards typically supported planar displays when the depth was less than eight. So for compatibility with programs from that era, you may well be getting a one-plane planar BitMap from AllocBitMap(). Of course that's going to require planar to chunky conversion when blitted to a 32-bit BitMap, which is going to be slow.
When calling AllocBitMapTags/TagList() I wonder if you're not getting something like an 8-bit color-mapped BitMap instead. It would use eight times as much memory (not as big an issue on an OS4 system), but would be much faster to blit to a truecolor BitMap.
As Capehill suggested, it might be instructive to query the BitMaps returned by the two different functions using GetBitMapAttr() to see how they compare.
BTW: I don't think it makes any difference with this issue, but the backBuffer BitMap doesn't really need to be BMF_DISPLAYABLE, since it is never displayed directly, but is always blitted to a displayable BitMap for display.
@joerg Thanks for the input, but the SDK does not say that AllocBitMap (V39) is obsolete or should not be used. Also, BMF_CHECKMASK is not documented in the Autodocs - at least not in the AllocBitMap section. Update: Sorry, it is in the Autodocs. I am getting blind...
@joerg + @msteed Thanks for the tip with GetBitMapAttr. These are the results:
Using BMF_MINPLANES with AllocBitMap seems to do the trick, this will also alloc a RTG bitmap instead of a legacy one. But I am not sure why - the SDK indicates that BMF_MINPLANES should not be used for performance reasons (?!?).
@FlynnTheAvatar Using depth >= 15 instead of 1 might work for getting a true colour RTG bitmap instead of a planar one with the old AllocBitMap() function without using BMF_CHECKMASK or BMF_MINPLANES (which is reserved for internal OS use and shouldn't be used by applications anyway). Edit: Removing BMF_DISPLAYABLE may help as well, even with depth 1. If it doesn't have to be displayable (on an planar OCS/ESC/AGA screen mode) it might return the same bitmap format as in the friend bitmap as well.
On AmigaOS 2.x/3.x there was no gfx card support in the OS yet and AllocBitMap() always returns a planar (OCS/ECS/AGA) bitmap, only with BMF_CHECKMASK the replacement functions patched into graphics.library by Picasso96 or CyberGraphX with additional features are used and can return 8 bit chunky or 15-32 bit true colour bitmaps. It was probably kept that way in AmigaOS 4.x for compatibility to old software. New AmigaOS 4.x software should use the new AmigaOS 4.x AllocBitMapTag[s|List]() function instead.
Thank you for the input. Removing BMF_DISPLAYABLE does not make any difference.
Using BMF_CHECKMASK seems to be the only portable way to make it work on multiple AmigaOS versions. It seems to work on AmigaOS 3.2, AmigaOS 3.9 and OS 4.1. Edit: Not really, this would break executing on a non-RTG system. Is there a way to test if the system has Picasso96/CyberGraphX installed?
BTW: Is the strategy to draw into a separate bitmap and then blitting it into the window's bitmap the correct way? Or is there a better way to have "double buffering" in windows?
BTW: Is the strategy to draw into a separate bitmap and then blitting it into the window's bitmap the correct way? Or is there a better way to have "double buffering" in windows?
It's the usual way, intuition and graphics.library only support double buffering for screens (IIntuition->[Alloc|Change|Free]ScreenBuffer()), not for windows.
Picasso96 has support for multi buffering PIP windows (check the Picasso96API autodoc), but it was only supported by some old gfx cards like Voodoo 3/5.
I imagine you're running the example program on a 32-bit truecolor Workbench screen, which means your friend BitMap is also 32-bit truecolor. But the backBuffer BitMap you're allocating has a depth of only one bit. So the question is, what happens when you ask for a one-bit color-mapped BitMap, but pass a 32-bit truecolor friend BitMap?
In both cases, 1 bit depth was asked for, but AllocBitMapTags() returned a different result.
Quote:
Back in the OS 3.1 days even graphics cards typically supported planar displays when the depth was less than eight. So for compatibility with programs from that era, you may well be getting a one-plane planar BitMap from AllocBitMap(). Of course that's going to require planar to chunky conversion when blitted to a 32-bit BitMap, which is going to be slow.
Well, actually, at 1 bit depth they are both chunky in a sense. The difference is one is palette based and the other is RGB based but both exist on one plane. So it would need to scale 1 bit to 32 bits for each pixel. But also, would need look up the palette colours, and write that in. It surely would have HW acceleration to scale 1 bit up to 32 per pixel but converting from bitmap to pixmap would kill it.
@FlynnTheAvatar The figures returned from the AllocBitMap() attributes don't look right. I wonder what is returned from OS3/68K?
The BMA_DEPTH is 1 but the rest are 0. I would expect BMA_BYTESPERPIXEL to be 1 at least. Though each pixel takes less with 1/8 a byte. But BMA_BITSPERPIXEL should definitely be 1.
1 bit RGB😲 1/3 bit R, 1/3 bit G and 1/3 bit B, or 1/4 bit Alpha, 1/4 bit R, 1/4 bit G and 1/4 bit B? 🤣
LOL.
None of the above. I mean palette based with an index. So even if we compare with 8 bit chunky it needs scaling with a LUT to a direct value. Indirect to direct.
No, the values are correct. BMA_ISRTG, BMA_BYTESPERPIXEL, BMA_BITSPERPIXEL, and BMA_PIXELFORMAT are only on AmigaOS 4.1, and are only filled when you have a RTG bitmap.
In both cases, 1 bit depth was asked for, but AllocBitMapTags() returned a different result.
Indeed it did. And while in retrospect, once you learn that AllocBitMap() and AllocBitMapTags/TagList() work differently from each other you can reason out why that is, I agree with FlynnTheAvatar that based on reading the autodocs that's not what you'd expect to happen.
It would be nice if the autodoc for AllocBitMap() could be updated to add a note that due to the need for backwards compatibility, you might not get an optimal BitMap for an RTG display even if you pass an RTG friend BitMap. Otherwise this is sure to catch someone else by surprise someday.
I mean palette based with an index. So even if we compare with 8 bit chunky it needs scaling with a LUT to a direct value. Indirect to direct.
Maybe it's surprising but 8 bit RGB modes really did exist in the 80s/90s, IIRC the Amiga Zorro III Merlin GFX card did support an R2G3B2 mode while all other (Amiga) gfx cards from that time were limited to CLUT (all supported 8 bit chunky modes, some additionally 8 bit planar modes) and YUV for <= 8 bits. But there never ever was any 1 bit RBG gfx card The RGB8 formats are irrelevant nowadays, only still required for MSX and Sega emulators maybe.
Except for such rare exceptions and YUV, no matter if it's planar or chunky, with <= 8 bits/pixel it's always a palette based mode with CLUT.