Android Tutorial [B4X] [BitmapCreator] Maximizing Performance with BC

Discussion in 'Tutorials & Examples' started by Erel, Jun 7, 2018.

  1. Erel

    Erel Administrator Staff Member Licensed User

    1. This tutorial is about BitmapCreator v3.5+.
    2. It is relevant for B4A, B4i and B4J.
    3. The features discussed are only needed when making hundreds or more drawings per second.

    Drawing Bitmaps

    When you call bc.DrawBitmap, a new BC is created, the pixels from the bitmap are copied to the new BC and then it is drawn with DrawBitmapCreator.
    It is better to convert the Bitmap to BC yourself and draw it with DrawBitmapCreator. It provides more options and it allows you to reuse the BC without copying the pixels from the bitmap each time.

    To Blend Or Not To Blend

    When SkipBlending is False, transparent and semi-transparent pixels in the source BC are blended (combined) with the target BC.

    SkipBlending = False:

    [​IMG]

    SkipBlending = True:

    [​IMG]

    Without optimizations, that will soon be discussed, drawing with SkipBlending = True can be 20+ times faster. It is much faster because the drawing is done by simply copying the data from one bytes array to another.

    One clear case where there is no reason to draw with blending is with solid BCs. The target BC will be overwritten anyway.

    Blending Optimizations

    As we do need to draw with blending in many cases we can make the drawing much faster with the following optimization:
    After the source BC is ready you should call bc.BuildPatternCache. A data structure is created that holds information about the solid, semitransparent and transparent pixels in the BC. Later when this BC is drawn over another BC this information will be used to improve the drawing performance.
    You only need to call bc.BuildPatternCache once (unless you later modify the BC).

    Code from GameUtils class that converts a bitmap to BC:
    Code:
    Public Sub BitmapToBitmapCreator (bmp As B4XBitmap, IgnoreSemiTransparent As Boolean) As BitmapCreator
       
    Dim bc As BitmapCreator
       bc.Initialize(bmp.Width, bmp.Height)
       bc.CopyPixelsFromBitmap(bmp)
       bc.BuildPatternCache (IgnoreSemiTransparent)
       
    Return bc
    End Sub
    As you can see in the above code we immediately call BuildPatternCache and forget about it.

    Drawing semi-transparent pixels is the slowest operation. To further improve the performance we can treat semi-transparent pixels as if they are solid or fully transparent (based on the alpha level). This is done by setting the IgnoreSemiTransparent parameter to True.

    IgnoreSemiTransparent = True:
    [​IMG]

    IgnoreSemiTransparent = False:
    [​IMG]

    Some numbers, tested with B4J:

    Mode .......................... Number of sprites per second
    SkipBlending=True .................... 1.1M+
    SkipBlending=False .................... 53K
    SkipBlending=False + bc.BuildPatternCache(False) 202K
    SkipBlending=False + bc.BuildPatternCache(True) 590K

    As you can see the improvement is huge.

    Asynchronous Drawings

    Instead of making the drawings with the main thread, we can build a list with all the drawing tasks and call bc.DrawBitmapCreatorsAsync. The drawings will be made with a background thread.
    It looks like this:
    Code:
    Wait For (MainBC.DrawBitmapCreatorsAsync(tasks)) Complete (bmp As B4XBitmap)
    Each item in the list is a DrawTask type that holds the same parameters that should be passed to DrawBitmapCreator.
    As a bonus it also returns the created bitmap.

    While the background thread is making the drawings, the main thread is free to do other things like receiving user input and updating the display.
    Note that you shouldn't do any other drawings with this BC until the Complete event is raised.

    Scale (B4A only):

    BitmapCreator creates bitmaps with a scale of 1.0. You should treat all devices as if their scale is 1.0.
    To create a BC with the same size as a View:
    Code:
    'this code will work correctly in all platforms
    bc.Initialize(ImageView1.Width / xui.Scale, ImageView1.Height / xui.Scale)
    If you are loading a bitmap then don't use 'dip' units.


    Final Result

     
    Last edited: Jun 7, 2018
    koaunglay, Jaames, XbNnX_507 and 10 others like this.
  2. desof

    desof Well-Known Member Licensed User

    one example ?
     
  3. Erel

    Erel Administrator Staff Member Licensed User

  4. Jaames

    Jaames Active Member Licensed User

    Fantastic :)
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice