Qbasicnews.com

Full Version: SDL speed increase using image = SDL_DisplayFormat(image)
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2
I just wanted to point out that image = SDL_DisplayFormat(image) seems to be a great way to get some free speed. It takes the bitmaps loaded in memory and changes them into the same format as the display, which seems to cause a non-trivial performance increase. It doubled the speed of a tile routine on my machine, but nearly tripled it on others.
Cool, and only now you told us about that? ;)

Btw, it's a good idea to delete the old surface, it won't be done by DisplayFormat() and check also for NULL's, i'm not sure if the surface is allocated in VRAM, that could run out of memory.
I learned about it last night helping out SCC with the pitiful speeds of his simple tile engine.

He actually gave me some great ideas for rewriting the qfak engine without it sucking. Smile
Yeah, the SDL manual clearly states that it uses this function to optimize surfaces.

Also, use different surfaces with fixed alpha values instead of changing a surfaces alpha value constantly. (ie: if water is 75% translucent, make a separate surface for water and set it's alpha to 192 once).

Also, use RLE all the time. SDL get's a great speed boost from this.

Store all surfaces in system memory, except the video surface. Keep a memory buffer to do all work on.

Do *not* use OpenGL blits, they are slower then software.

I found all these things to be true when working on the tile engine for my FF remake.

This is the detection code I use to have the game set the optimal settings based on system availability:
Code:
    Dim Shared Desktop                        As SDL_VideoInfo Ptr
    Dim Shared Video                            As SDL_Surface Ptr
    Dim Shared Buffer                            As SDL_Surface Ptr
    Dim Shared TilePalettes( 0 To 7 )    As SDL_Surface Ptr

    Dim Shared VideoSurfaceType            As UInteger
    Dim Shared BufferSurfaceType            As UInteger
    Dim Shared TilePalettesType(0 To 7)    As UInteger


Sub ThisShouldBeInYourSDLInitSub ()

    '' Get desktop settings
    Desktop = SDL_GetVideoInfo

    '' Default software surfaces
    VideoSurfaceType      = SDL_SWSURFACE Or SDL_ASYNCBLIT
    BufferSurfaceType     = SDL_SWSURFACE Or SDL_RLEACCEL Or SDL_RLEACCELOK
    For X = 0 To 7
        TilePalettesType(x)= SDL_SWSURFACE Or SDL_RLEACCEL Or SDL_RLEACCELOK
    Next X

    If ( Instr( Command$, "-f" ) Or Instr( Command$, "-F" ) ) Then VideoSurfaceType = VideoSurfaceType Or SDL_FULLSCREEN

    '' Make sure hardware surfaces are available
    If ( ( Desktop->flagBits ) And SDL_HW_AVAILABLE ) Then

        '' Hardware blits accelerated?
        If ( ( Desktop->flagBits ) And SDL_BLIT_HW ) Then

            '' Define the video surface as hardware accelerated and in video memory
            VideoSurfaceType = VideoSurfaceType Or SDL_HWSURFACE Or SDL_HWACCEL

            '' Hardware->Hardware colour-keyed and alpha blits must be accelerated for hardware buffers & accel
            If ( ( ( Desktop->flagBits ) And SDL_BLIT_HW_CC ) And ( ( Desktop->flagBits ) And SDL_BLIT_HW_A ) ) Then

                BufferSurfaceType      = BufferSurfaceType   Or SDL_HWSURFACE Or SDL_HWACCEL
                For X = 0 To 7
                    TilePalettesType(x) = TilePalettesType(X) Or SDL_HWSURFACE Or SDL_HWACCEL
                Next X

            Else

                '' Software->Hardware colour-keyed blits must be accelerated for hardware accel
                If ( ( Desktop->flagBits ) And SDL_BLIT_SW_CC ) Then

                    BufferSurfaceType = BufferSurfaceType Or SDL_HWACCEL

                End If

                '' Software->Hardware colour-keyed and alpha blits must be accelerated for hardware accel
                If ( ( ( Desktop->flagBits ) And SDL_BLIT_SW_CC ) And ( ( ( Desktop->flagBits ) And SDL_BLIT_SW_A ) ) ) Then

                    For X = 0 To 7
                        TilePalettesType(x) = TilePalettesType(X) Or SDL_HWACCEL
                    Next X

                End If

            End If

        End If

    End If

End Sub

Your surface load code would use the appropriate surface type or tile palette type as the flags during creation. This allows my code to get maximum preformance from available system resources.
1000101 what about static bitmaps i.e. a tileset that your not going to ever change at runtime wouldn't it be better to have that in VRAM ? so sdl can take advange of hardware bliting ?
Shadow: You'd think so, but as it turns out, no. Because any single surface being in system memory will cause the entire system to run slow. So, to make it run as fast as possable, we put all surfaces in system memory and transfer them once to video memory.

Also, I forgot the accompanying functions.

CreateBackBuffer requires that a video surface is created before being called.

CreateSurfaceFromFile requires that a back-buffer is created before being called.

CreateSurfaceFromFile takes a packed 24-bit RGB format colour for the transparency and converts it internally to the surface format.

Code:
Function CreateBackBuffer ( ByVal VideoSurface As SDL_Surface ) As SDL_Surface Ptr

    Dim tmpSurface                        As SDL_Surface Ptr
    Dim ReturnSurface                    As SDL_Surface Ptr

    CreateBackBuffer = 0

    '' Create a compatable surface
    tmpSurface = SDL_CreateRGBSurface( VideoSurface->flags, _
                                      VideoSurface->w, VideoSurface->h, _
                                      VideoSurface->format->BitsPerPixel, _
                                      VideoSurface->format->Rmask, _
                                      VideoSurface->format->Gmask, _
                                      VideoSurface->format->Bmask, _
                                      VideoSurface->format->Amask )
    If ( tmpSurface = 0 ) Then    Goto CreateBackBuffer_Abort

    '' Convert it to the proper format
    ReturnSurface = SDL_ConvertSurface ( tmpSurface, Video->Format, BufferSurfaceType )
    If ( ReturnSurface = 0 ) Then Goto CreateBackBuffer_Abort

    '' Now do a blit to force the optimizations
    SDL_BlitSurface ReturnSurface, ByVal 0&, tmpSurface, ByVal 0&

    '' Release the temp surface
    SDL_FreeSurface tmpSurface

    '' Return the proper surface
    CreateBackBuffer = ReturnSurface

    Exit Function

CreateBackBuffer_Abort:
    '' Release the temp surface

    If ( tmpSurface ) Then SDL_FreeSurface tmpSurface

End Function


Function CreateSurfaceFromFile    (    ByRef Pathname As String, _
                                                ByVal Flags As UInteger, _
                                                ByVal Transparent As Integer, _
                                                ByVal Alpha As Integer _
                                            ) As SDL_Surface Ptr

    Dim tmpSurface                        As SDL_Surface Ptr
    Dim ReturnSurface                    As SDL_Surface Ptr

    CreateSurfaceFromFile = 0

    '' Load the image to a temp surface
    tmpSurface = IMG_Load( Pathname )
    If ( tmpSurface = 0 ) then
        ErrorMessage = *SDL_GetError()
        MessageBox 0, _
            ErrorMessage, _
            "Error", _
            MB_OK
        Denit
        End 1
    End If

    '' Set the transparent, if any
    If ( Transparent <> FF_NO_COLOURKEY ) Then
        Flags = Flags Or SDL_SRCCOLORKEY
        SDL_SetColorKey tmpSurface, Flags, SDL_MapRGB( tmpSurface->Format, ( ( Transparent Shr 16 ) And &B11111111 ), ( ( Transparent Shr 8 ) And &B11111111 ), ( Transparent And &B11111111 ) )
    End If

    '' Set the alpha, if any
    If ( Alpha <> SDL_ALPHA_OPAQUE ) Then
        Flags = Flags Or SDL_SRCALPHA
        SDL_SetAlpha tmpSurface, Flags, Alpha
    End If

    '' Convert it to the proper format
    ReturnSurface = SDL_ConvertSurface ( tmpSurface, Buffer->Format, Flags )
    If ( ReturnSurface = 0 ) then
        ErrorMessage = *SDL_GetError()
        MessageBox 0, _
            ErrorMessage, _
            "Error", _
            MB_OK
        Denit
        End 1
    End If

    '' Now do a blit to force the optimizations
    SDL_BlitSurface ReturnSurface, ByVal 0&, Buffer, ByVal 0&
    
    '' Release the temp surface
    SDL_FreeSurface tmpSurface

    '' Return the proper surface
    CreateSurfaceFromFile = ReturnSurface

End Function
that still doesn't make sence i mean if your storing your tileset in vram in the card own memorey right. so hardware should have a easyer time moving stuff around in vram.
You would think so, but SDL's hardware support in windows is through an *early* implementation of DirectX which requires very specialized hardware functionality. A smarter method, which it doesn't use, would be to render a surface as a pair of triangles using texture mapping hardware.

I did this myself in VB and would routinely get 500+ FPS with fullscreen alphablending and lighting. I'm starting to do it now in OpenGL in FB with similar results.

However.

Since SDL uses software alpha blending, if the source or destination surface is in hardware, then it will be slow. There is no gain putting the source in hardware, so it may as well be system memory so it's marginally faster. If you do a lot of alpha blending, then you may as well put the destination in system memory to get the most speed. Now, if your destination buffer is in system memory, then the rest of your surfaces will take a hit if they are in hardware. The solution? All surfaces in system memory.

Now, if you only blend one or two small tiles, then you can put the surfaces in hardware and take the hit on the couple alpha blends. But, you will find that if even 10% of the scene is alpha blended, it will be slower then if all the surfaces are in system memory.

Another thing to note, is that I found SDL doesn't handle tile palettes more then 256 pixels wide very well. So, if you want 256 tiles per palette and your tiles are 32x32, then make it 8 tiles wide and 32 tiles tall (256x1024).

I hope this helps explain my logic of putting all surfaces except the video surface in system memory.

More helper functions:
Code:
Sub BlitTile ( ByVal TileIndex As Short, ByVal DstX As Integer, ByVal DstY As Integer, ByVal DstSfc As SDL_Surface Ptr )

    '' Blits a tile to destination surface given a packed Tile Index
    '' including tile palette, Tile X, Tile Y.
    ''
    '' Bits:   Meaning:
    '' 0-2     Tile X
    '' 3-11    Tile Y
    '' 12-15   Tile Palette
    ''
    '' This allows for 64K tiles stored 8x256 in 8 palettes.
    '' Each palette, as a result, can be categorized with similar
    '' render characteristics.  ie:  Palette 0 can no transparency,
    '' no alpha; palette 1 can be transparency, alpha 128; palette
    '' 2 can be transparency, no alpha; etc.
    ''
    '' Routine expects SCREEN_WIDTH, SCREEN_HEIGHT, TILE_WIDTH and
    '' TILE_HEIGHT constants to be set beforehand.

    Dim TilePal As Integer

    Dim dstRect As SDL_Rect
    Dim srcRect As SDL_Rect

    '' This check is for layering, tile 7FF (7, 255 (2047) in any palette)
    '' means no tile.
    If ( ( TileIndex And &H7FF ) = &H7FF         ) Then Exit Sub

    If (                    DstX > SCREEN_WIDTH  ) Then Exit Sub
    If (                    DstY > SCREEN_HEIGHT ) Then Exit Sub
    If (  ( DstX + TILE_WIDTH  ) < 0             ) Then Exit Sub
    If (  ( DstY + TILE_HEIGHT ) < 0             ) Then Exit Sub

    With srcRect
        .x =           ( TileIndex And &H0007 ) * TILE_WIDTH
        .y = ( ( TileIndex Shr 3 ) And &H00FF ) * TILE_HEIGHT
        .w = TILE_WIDTH
        .h = TILE_HEIGHT
    End With

    With dstRect
        .x = DstX
        .y = DstY
        .w = TILE_WIDTH
        .h = TILE_HEIGHT
    End With

    TilePal = ( ( TileIndex Shr 11 ) And &H7 )

    SDL_BlitSurface TilePalettes( TilePal ), @srcRect, DstSfc, @dstRect

End Sub

Function MakeTile ( ByVal X As Byte, ByVal Y As Byte, ByVal TilePal As Byte ) As Short

    '' Creates a tile index compatable with BlitTile.

    MakeTile = ( ( TilePal And &H7 ) Shl 11 ) Or ( ( Y And &HFF) Shl 3 ) Or ( X And &H7 )

End Function
1000101: If your hardware supports it, you can do hardware blits, which is WAY faster than using system mem, if hardware blits are available, putting statis bmps in vmem will give a speedboost..

However, if you're going to alter the bitmaps a lot, system mem is faster, also, if the card doesent have hardware blits, system mem blits are again faster.

Same goes for blending, some cards have hardware blending, those who have will benefit if you put the surfaces in vmem before blending them..
If the card doesent have hardware blending, having them in system mem is again faster..
Ok, a) has anyone read the SDL manual besides me? And b) has anyone actually done benchmarks besides me?

A) The manual clearly states that SDL uses a software routine to do blending and does *not* use hardware since the interface it uses does *not* have an alpha-blend function (dx 3).

B) I have. When using hardware acceleration, then yes. These things are very fast, but that fast remains that SDL does *not* use hardware accel for alpha blending in win32. If it did, then it would be faster, but, since it doesn't, it isn't.

So, inconclusion, put yer money where your mouth is. Theory is fine and all, but without an experiment confirming this, it's meaningless. I know that using the hardware to accelerate blits is faster, but SDL uses an antiquated system which some cards don't support the interface to anymore, also this interface wasn't very advanced so it had to do it in software, ie: alpha blitting.

Just because something works well with one API, doesn't mean it works well with another.
Pages: 1 2