Super fast Linux splashscreen

Bobsleigh race picture

Here’s a simple trick that I recently rediscovered when I worked on a boot time reduction project for a customer. It’s not rocket science, but you may not be aware of it.

Our customer was using fbv to display its logo right after the system booted. This is a way to show that the system is available while you’re starting the system’s main application:

fbv -d 1 /root/logo.bmp > /dev/null 2>&1

With Grabserial and using simple instrumentation with messages issued on the serial console before and after running the command, we found that this command was taking 878 ms to execute. The customer’s system had an AT91SAM9263 ARM SOC from Atmel, running at 200 MHz.

Even if fbv is a simple program (22 KB on ARM, compiled with shared libraries), decoding the logo image is still expensive. Here’s a way to get this compute cost out of your boot sequence. All you have to do is display your logo on your framebuffer, and then capture the framebuffer contents in a file:

fbv -d 1 /root/logo.bmp
cp /dev/fb0 /root/logo.fb

The new file is now a little bigger, 230400 bytes instead of 76990. However, displaying your boot logo can now be done by a simple copy:

dd if=/root/logo.fb of=/dev/fb0 bs=230400 count=1 > /dev/null 2>&1

This command now runs in only 54 ms. That’s only 6% of the initial execution time! The advantage of this approach is that it works with any kind of framebuffer pixel format, as long as you have at least one program that knows how to write to your own framebuffer.

Note that the dd command was used to read and write the logo in one shot, rather than copying in multiple chunks. We found that the equivalent cp and cat commands were slightly slower. Of course, the benchmark results will vary from one system to another. Our customer had heavily optimized their NOR flash access time. If you run this on a very slow storage device, using a much faster CPU, the time to display the logo may be several impacted by the time taken to read a bigger file from slower storage.

To get even better performance, another trick is to compress the framebuffer contents with LZO (supported by BusyBox), which is very fast at decompressing, and requires very little memory to run:

lzop -9 /root/logo.fb

The new /root/logo.fb.lzop file is now only 2987 bytes big. Of course, the compression rate will depend on your logo image. In our case, the splashscreen contains mostly white space and a simple monochrome company logo. The new command to put in your startup scripts is now:

lzopcat /root/logo.fb.lzo > /dev/fb0

The execution time is now just 52.5 ms! With a faster CPU, the time reduction would have been even bigger.

The ultimate trick for having a real and possibly animated splashscreen would be to implement your own C program, directly writing to the framebuffer memory in mmap() mode. Here’s a nice tutorial showing how easy it can be.

Author: Michael Opdenacker

Michael Opdenacker is the founder of Bootlin, and was its CEO until 2021. He is best known for all the free embedded Linux and kernel training materials that he created together with Thomas Petazzoni. He is always looking for ways to increase performance, reduce size and boot time, and to maximize Linux' world domination. More details...

22 thoughts on “Super fast Linux splashscreen”

    1. Sure, lots of people do it too. You just have to hack the bootloader and implement a simple framebuffer driver inside it.

      With Linux, that’s easier as the driver is already available.

      Michael.

  1. Have you inquired into the source of the original slowness of fbv .bmp display: is it fbv or the BMP image format? (If it’s the former, maybe we should try to improve it too ; if it’s the latter, well… you have already given some solutions but maybe using a different format would help too.)

    1. Hi Rodolphe,

      No, I haven’t investigated the exact cause of fbv’s slowness. Looking at the code, I just suspected that the CPU intensive parts lied in image format decoding. However, fbv could have its own issues too.

      Thanks,

      Michael.

  2. Hi Michael
    I have tried this
    fbv -d 1 /root/logo.bmp
    cp /dev/fb0 /root/logo.fb

    the new logo.fb is 4.3 mb big while the bmp image I used was 2kb. I took another bmp image and again it was 4.3 mb. Am I missing something?

  3. Hi Michael,
    This is nice info about frame buffer. I need same but slight change. I tried fbv – on ARM board – saying command not found and not able to find the screen change while using /dev/fb0. i am looking for bootup-logo screen change. i am using frame buffer and mmap functions from user-space program but unable to.

    i tried with some pixel values we send to the /dev/fb0 then i am getting some rectangle box with some color — as given value.

    Now i need to change that program with jpg image. can you help in this.

    regards,

    Viswanath K

      1. Thank you for the reply. In my build, those packages are having. so i am tried to write a small frame-buffer application program, it is working with bmp files. Not able to load the jpeg , i think jpeg decoder or an fbi(image viewer)is required. There is a link libexif and fbida – but not able to load in board(AM335x-sitara kit).

        regards,

        Viswanath K

  4. Hi Michael, I came across your blog while I was researching ways to hide splash screens and logs that Linux is spewing while it’s booting up. I was thinking to display company logo from a frame buffer, keep displaying while the system boots and then switch to the normal frame buffer when the application starts.

    Can you give me some pointers and ideas if this is possible to do?

    I’m using x86-64 SBC and Ubuntu 14.04 as embdedded distribution.

    Regards, Dragan

    1. Android is a bit out of topic, here. You could hack the way it boots and display a custom spashscreen, but it’s probably best to use Android’s own mechanisms (sorry, I don’t have them in mind… you’ll have to look them up).

  5. Thanks for sharing. Very Helpful.
    How can we show animated splash or video splash within 1 sec requirement?

    Regards,
    Vikas

  6. Thanks for sharing this tricks.
    Will be very helpful.

    I’m using buildroot 2016.08.01 to generate a rootfs for the Freescale iMX6 SoloX Sabre SD board and I don’t find where to get lzopcat.

    I found lzop in the buildroot package list and in the busybox config but no way to find lzopcat.

    A google search didn’t give me the solution.

    Where can I fint this lzopcat utility ?
    Regards

    1. Just try a “make install” after selecting lzop in the configuration. You will find a usr/bin/lzopcat file. At least I checked that with the latest git sources.

      You may also try with “lzop -c”, which should be equivalent to lzopcat.

      Michael

  7. That’s some nice info.
    It’s a little bit out of topic but do you by any chance know how to draw to “permanently” (or at least as long as a setup script is running that uses dialog) set a image/logo at a certain position without it disappearing or interrupting other processes that print out stuff?

      1. That’s a nice hint.
        I’m concerned wether there might be a problem with the program “dialog” tho since I use this during aa setup script and when I draw to the framebuffer normally the dialog paints over that.
        I will check out what the raspberry guys did,
        thanks for answering (even after years after this blog post was made), Michael!

      2. The thing is that it should only be visible once:
        While doing the setup after booting from a the setup usb stick. In the end the server should not be different from already existing ones; only temporary changes are okay that don’t persist a reboot.

    1. As a quick follow up..

      I kind of achieved what I wanted to achieve (displaying something while a script that is using dialog is running).
      Actually I already knew about https://unix.stackexchange.com/a/192811 but for some reason I did not add 2> /dev/null to dd, which ended up printing a line which caused dialog to repaint over the pixel.

      Whatever, at some point I started to try to paint pixel to the framebuffer by using the C language. And (at that time I still believed that it couldn’t be done with dd) to my surprise dialog did not repaint until the next dialog was opened.
      My final code isn’t that efficient, but it can be written in just a few hours.
      Basically I convert images to text using convert (ImageMagick), sed out stuff until I only get lines that are like X Y RRGGBBAA and then I read them line by line and each time I put a pixel on the screen. That is most likely not how it should be done but I had nearly zero experience with libpng, I wanted to keep it simple and I only had some limited time.

      Three sites helped me a lot:
      http://betteros.org/tut/graphics1.php
      https://www.i-programmer.info/programming/cc/12839-applying-c-framebuffer-graphics.html?start=1 (RGBA shifting part)
      https://gist.github.com/FredEckert/3425429

      So, yeah. I just call the compiled program in the background while the script that is using dialog is running:

      while /bin/true; do
      ./draw_fb png.txt
      sleep 0.1
      done &
      FBIMG_PID=$!
      trap ‘kill -9 $FBIMG_PID’ EXIT

Leave a Reply to Dragan Ostojic Cancel reply