Login
Username:

Password:

Remember me



Lost Password?

Register now!

Sections

Who's Online
106 user(s) are online (91 user(s) are browsing Forums)

Members: 2
Guests: 104

Raziel, Paul, more...

Support us!

Headlines

 
  Register To Post  

(1) 2 »
AllocBitMap vs AllocBitMapTags
Just popping in
Just popping in


See User information
Hi,

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.

Thanks,
Flynn

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

/* our system libraries addresses */
struct LibraryGfxBase NULL;
struct GraphicsIFaceIGraphics NULL;
struct LibraryIntuitionBase NULL;
struct IntuitionIFaceIIntuition NULL;

struct RenderEngineData
{
    
struct Windowwindow;
    
struct tPoint outputSize;
    
struct BitMapbackBuffer;
    
struct tPoint backBufferSize;
    
struct RastPort renderPort;
    
int returnCode;
    
BOOL run;
    
BOOL doRepaint;
    
BOOL doRender;
};

void RepaintWindow(struct RenderEngineDatard)
{
    
/* on repaint we simply blit our backbuffer into our window's RastPort */
    
IGraphics->
     
BltBitMapRastPort(rd->backBuffer00rd->window->RPort,
                      (
LONG)rd->window->BorderLeft,
                      (
LONG)rd->window->BorderTop,
                      (
LONG)rd->outputSize.x, (LONG)rd->outputSize.y,
                      (
MINTERM_ABNC MINTERM_ABC));
}

int PrepareBackBuffer(struct RenderEngineDatard)
{
    
int result;

    if(
rd->outputSize.!= rd->backBufferSize.||
       
rd->outputSize.!= rd->backBufferSize.y)
    {
        
/* if output size changed free our current bitmap... */
        
if(rd->backBuffer)
        {
            
IGraphics->FreeBitMap(rd->backBuffer);
            
rd->backBuffer NULL;
        }

        
/* ... allocate a new one... */
        /* DO NOT USE AllocBitMap - IT IS EXTREMELY SLOW WHEN BLITTING
         * /
        rd->backBuffer = IGraphics->AllocBitMap((ULONG)rd->outputSize.x,
                                                (ULONG)rd->outputSize.y,
                                                1,
                                                BMF_CLEAR|BMF_DISPLAYABLE,
                                                rd->window->RPort->BitMap);
        */
        
rd->backBuffer IGraphics->AllocBitMapTags((ULONG)rd->outputSize.x,
                                                    (
ULONG)rd->outputSize.y,
                                                    
1,
                                                    
BMATags_Friendrd->window->RPort->BitMap,
                                                    
BMATags_ClearTRUE,
                                                    
BMATags_DisplayableTRUE,
                                                    
TAG_DONE);
        
/**/
        
if(rd->backBuffer)
        {
            
/* and on success remember its size */
            
rd->backBufferSize rd->outputSize;
        }

        
/* link the bitmap into our render port */
        
IGraphics->InitRastPort(&rd->renderPort);
        
rd->renderPort.BitMap rd->backBuffer;
    }

    
result rd->backBuffer RETURN_OK RETURN_ERROR;

    return 
result;
}

int RenderBackbuffer(struct RenderEngineDatard)
{
    
int result;

    
result PrepareBackBuffer(rd);

    if(
result == RETURN_OK)
    {
        
struct RastPortrastPort;
        
struct tPoint maxPos;
        
struct tPoint lineStep;
        
struct tPoint pos;
        
WORD i;

        const 
WORD stepCount 32;

        
/* we make a local copy of our RastPort pointer for ease of use */
        
rastPort = &rd->renderPort;

        
/* clear our bitmap */
        
IGraphics->SetRast(rastPort0);

        
/* now draw our line pattern */
        
maxPos.rd->backBufferSize.1;
        
maxPos.rd->backBufferSize.1;

        
lineStep.maxPos.stepCount;
        
lineStep.maxPos.stepCount;

        
IGraphics->SetAPen(rastPort1);
        
pos.pos.0;
        for(
0i Move(rastPort0, (LONG)pos.y);
            
IGraphics->Draw(rastPort, (LONG)(maxPos.pos.x), 0);
            
IGraphics->Draw(rastPort, (LONG)maxPos.x, (LONG)(maxPos.pos.y));
            
IGraphics->Draw(rastPort, (LONG)pos.x, (LONG)maxPos.y);
            
IGraphics->Draw(rastPort0, (LONG)pos.y);

            
pos.+= lineStep.x;
            
pos.+= lineStep.y;
        }
    }

    return 
result;
}

void ComputeOutputSize(struct RenderEngineDatard)
{
    
/* our output size is simply the window's size minus its borders */
    
rd->outputSize.=
    
rd->window->Width rd->window->BorderLeft rd->window->BorderRight;
    
rd->outputSize.=
    
rd->window->Height rd->window->BorderTop rd->window->BorderBottom;
}

void DispatchWindowMessage(struct RenderEngineDatard,
                           
struct IntuiMessagemsg)
{
    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);
            }

            
IIntuition->EndRefresh(rd->windowTRUE);
            break;
        }
    }
}

int MainLoop(struct RenderEngineDatard)
{
    
struct MsgPortwinport;
    
ULONG winSig;

    
/* remember the window port in a local variable for more easy use */
    
winport rd->window->UserPort;

    
/* create our waitmask for the window port */
    
winSig 1 doRender TRUE;

    
/* we need to compute our output size initially */
    
ComputeOutputSize(rd);

    
/* enter our main loop */
    
while(rd->run)
    {
        
struct Messagemsg;

        if(
rd->doRender)
        {
            
rd->returnCode RenderBackbuffer(rd);
            if(
rd->returnCode == RETURN_OK)
            {
                
/* Rendering succeeded, we need to repaint */
                
rd->doRepaint TRUE;
                
rd->doRender FALSE;
            }
            else
            {
                
/* Rendering failed, do not repaint, leave our main
                 * loop instead */
                
rd->doRepaint FALSE;
                
rd->run FALSE;
            }
        }

        if(
rd->doRepaint)
        {
            
RepaintWindow(rd);
            
rd->doRepaint FALSE;
        }

        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);
        }
    }

    if(
rd->backBuffer)
    {
        
IGraphics->FreeBitMap(rd->backBuffer);
        
rd->backBuffer NULL;
    }

    return 
rd->returnCode;
}

int RunEngine(void)
{
    
struct RenderEngineDatard;

    
/* as long we did not enter our main loop we report an error */
    
int result RETURN_ERROR;

    
/* allocate the memory for our runtime data and ititialize it
     * with zeros */
    
if ((rd = (struct RenderEngineData*)
             
IExec->AllocVecTags(sizeof(struct RenderEngineData),
                 
AVT_TypeMEMF_PRIVATE,
                 
AVT_ClearWithValue0,
             
TAG_DONE)))
    {
        
/* now let's open our window */
        
static struct NewWindow newWindow =
        {
            
014,
            
320160,
            (
UBYTE)~0, (UBYTE)~0,
            
IDCMP_CLOSEWINDOW IDCMP_NEWSIZE IDCMP_REFRESHWINDOW,
            
WFLG_CLOSEGADGET WFLG_DRAGBAR WFLG_DEPTHGADGET |
            
WFLG_SIMPLE_REFRESH WFLG_SIZEBBOTTOM WFLG_SIZEGADGET,
            
00,
            
"Gfx Workshop",
            
0,
            
0,
            
9648,
            (
UWORD)~0, (UWORD)~0,
            
WBENCHSCREEN
        
};
        if((
rd->window IIntuition->OpenWindow(&newWindow)))
        {
            
/* the main loop will run as long this is TRUE */
            
rd->run TRUE;

            
result MainLoop(rd);

            
/* cleanup: close the window */
            
IIntuition->CloseWindow(rd->window);
            
rd->window NULL;
        }

        
/* free our runtime data */
        
IExec->FreeVec(rd);
        
rd NULL;
    }

    return 
result;
}

int main(int argccharargv[])
{
    
/* as long we did not execute RunEngine() we report a failure */
    
int result RETURN_FAIL;

    
/* we need at least 4.0 graphic.library's drawing functions */
    
if((GfxBase IExec->OpenLibrary("graphics.library"50)))
    {
        
/* load interface */
        
if((IGraphics = (struct GraphicsIFace*)
                
IExec->GetInterface(GfxBase"main"1NULL)))
        {
            
/* we need at least 4.0 intuition.library for our window */
            
if((IntuitionBase =
                    
IExec->OpenLibrary("intuition.library"50)))
            {
                
/* load interface */
                
if((IIntuition = (struct IntuitionIFace*)
                        
IExec->GetInterface(IntuitionBase"main"1NULL)))
                {
                    
/* All libraries needed are available, so let's run... */
                    
result RunEngine();

                    
IExec->DropInterface((struct Interface*)IIntuition);
                    
IIntuition NULL;
                }
                
IExec->CloseLibrary(IntuitionBase);
                
IntuitionBase NULL;
            }
            
IExec->DropInterface((struct Interface*)IGraphics);
            
IGraphics NULL;
        }
        
IExec->CloseLibrary(GfxBase);
        
GfxBase NULL;
    }

    return 
result;
}

Go to top
Re: AllocBitMap vs AllocBitMapTags
Home away from home
Home away from home


See User information
@FlynnTheAvatar

some older function warp to newer functions.
the fastest i think is TagList not Tags.

(NutsAboutAmiga)

Basilisk II for AmigaOS4
AmigaInputAnywhere
Excalibur
and other tools and apps.
Go to top
Re: AllocBitMap vs AllocBitMapTags
Just popping in
Just popping in


See User information
@LiveForIt

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.

That should not be that case.

Go to top
Re: AllocBitMap vs AllocBitMapTags
Home away from home
Home away from home


See User information
@FlynnTheAvatar

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.
Go to top
Re: AllocBitMap vs AllocBitMapTags
Just popping in
Just popping in


See User information
@LiveForIt

Both calls use the same flags and the same friend bitmap. So, why should there be a difference?

Go to top
Re: AllocBitMap vs AllocBitMapTags
Just can't stay away
Just can't stay away


See User information
@FlynnTheAvatar

Did you try to query bitmap attributes after its creation? Maybe that shows some difference.

Go to top
Re: AllocBitMap vs AllocBitMapTags
Just can't stay away
Just can't stay away


See User information
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.


Edited by joerg on 2023/2/19 20:39:44
Go to top
Re: AllocBitMap vs AllocBitMapTags
Just popping in
Just popping in


See User information
@FlynnTheAvatar

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

Go to top
Re: AllocBitMap vs AllocBitMapTags
Just popping in
Just popping in


See User information
@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:

AllocBitMap:
Bitmap flags10
BMA_DEPTH
1
BMA_ISRTG
0
BMA_BYTESPERPIXEL
0
BMA_BITSPERPIXEL
0
BMA_PIXELFORMAT
0

AllocBitMapTags
:
Bitmap flags0
BMA_DEPTH
24
BMA_ISRTG
1
BMA_BYTESPERPIXEL
4
BMA_BITSPERPIXEL
32
BMA_PIXELFORMAT
6

AllocBitMap with BMF_MINPLANES
:
Bitmap flags0
BMA_DEPTH
24
BMA_ISRTG
1
BMA_BYTESPERPIXEL
4
BMA_BITSPERPIXEL
32
BMA_PIXELFORMAT
6


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 (?!?).


Edited by FlynnTheAvatar on 2023/2/20 11:42:45
Go to top
Re: AllocBitMap vs AllocBitMapTags
Just can't stay away
Just can't stay away


See User information
@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.


Edited by joerg on 2023/2/20 13:21:41
Go to top
Re: AllocBitMap vs AllocBitMapTags
Just popping in
Just popping in


See User information
@joerg

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?

Go to top
Re: AllocBitMap vs AllocBitMapTags
Just can't stay away
Just can't stay away


See User information
@FlynnTheAvatar
Quote:
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?
Something like
BOOL RTG FALSE:
struct Library *lib;
if (
GfxBase->LibNode.lib_Version >= 50)
   
RTG TRUE;
else if ((
lib IExec->OpenLibrary("Picasso96API.library"0)))
{
   
RTG TRUE;
   
IExec->CloseLibrary(lib);
} else if ((
lib IExec->OpenLibrary("cybergraphics.library"0)))
{
   
RTG TRUE;
   
IExec->CloseLibrary(lib);
}
should work.

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

Go to top
Re: AllocBitMap vs AllocBitMapTags
Just popping in
Just popping in


See User information
@joerg

Thank you, trying to load the Picasso96 and cybergraphics.library to check for RTG works great.

Go to top
Re: AllocBitMap vs AllocBitMapTags
Not too shy to talk
Not too shy to talk


See User information
@msteed

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

Go to top
Re: AllocBitMap vs AllocBitMapTags
Just can't stay away
Just can't stay away


See User information
@Hypex
Quote:
The difference is one is palette based and the other is RGB based but both exist on one plane.
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? 🤣

Go to top
Re: AllocBitMap vs AllocBitMapTags
Not too shy to talk
Not too shy to talk


See User information
@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.

Go to top
Re: AllocBitMap vs AllocBitMapTags
Not too shy to talk
Not too shy to talk


See User information
@joerg

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

Go to top
Re: AllocBitMap vs AllocBitMapTags
Just popping in
Just popping in


See User information
@Hypex

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.

Please see here:
http://amigadev.elowar.com/read/ADCD_ ... cs_3._guide/node02E1.html

Go to top
Re: AllocBitMap vs AllocBitMapTags
Just popping in
Just popping in


See User information
Quote:
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.

Go to top
Re: AllocBitMap vs AllocBitMapTags
Just can't stay away
Just can't stay away


See User information
@Hypex
Quote:
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.

Go to top

  Register To Post
(1) 2 »

 




Currently Active Users Viewing This Thread: 3 ( 0 members and 3 Anonymous Users )




Powered by XOOPS 2.0 © 2001-2024 The XOOPS Project