
Writing to the Framebuffer (2018) - p4bl0
http://seenaburns.com/2018/04/04/writing-to-the-framebuffer/
======
ablu
My understanding was that fbdev is deprecated (but I was unable to find good
info on this) and that one should use dumb buffers
([https://manpages.debian.org/testing/libdrm-dev/drm-
memory.7....](https://manpages.debian.org/testing/libdrm-dev/drm-
memory.7.en.html)) for this simple stuff / somewhat portable software
rendering. At least Qt allows to do this for embedded devices without hardware
rendering.

~~~
Jasper_
Yes. fbdev is kept alive for compatibility (and fbcon) reasons, but it's a
really outdated API and drivers have to jump through hoops to support it.
Please use dumb buffers when necessary. See a simple example here:
[https://github.com/magcius/drmdemo](https://github.com/magcius/drmdemo)

~~~
rowanG077
How can I write a simple device driver using dumb buffers? I have searched far
and wide but I can't find anything. I'm forced to write a framebuffer driver.
Once you dip into DRI shit get's insanely complex quick.

~~~
Jasper_
For the simplest case, where you have contiguous memory for your framebuffer
storage and no MMIO, try the CMA helpers:
[https://github.com/torvalds/linux/blob/master/drivers/gpu/dr...](https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/drm_gem_cma_helper.c)

I wrote a basic device driver for a platform I worked on. It's since been
upstreamed and gotten more eyeballs, but it's still relatively simple.
[https://github.com/torvalds/linux/blob/master/drivers/gpu/dr...](https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/meson/meson_drv.c)

------
jschwartzi
This is something I exploit to do an early splashscreen to HDMI on the i.MX6.
The kernel splashscreen is supported with LVDS but not HDMI on the kernel that
ships for that SOC so as a workaround I take a bitmap representation in the
color depth of the framebuffer and cat it into /dev/fb0 while in the initial
ramdisk.

------
oldsklgdfth
This is a similar tutorial in C.

[http://betteros.org/tut/graphics1.php#fbdev](http://betteros.org/tut/graphics1.php#fbdev)

For a few months I've been kicking around the idea of making a mario clone
using this. You boot the machine and you just get the game.

EDIT: for 2D graphics, you can blit sprites in with the CPU. GPUs are mainly
useful for 3D graphics, physics and raytracing. Also, I made a mario clone in
Unity and Unity felt like overkill.

~~~
zozbot234
> GPUs are mainly useful for 3D graphics, physics and raytracing.

GPU's are quite usable as sprite engines. A Wayland compositor is essentially
blitting client-controlled sprites as "surfaces", and the final render is
pixel perfect (other than perhaps during animations). There's no reason
whatsoever to use software rendering if hardware acceleration is available.

~~~
justin66
> There's no reason whatsoever to use software rendering if hardware
> acceleration is available.

The really obvious one is that you might like to have a program that will work
with or without hardware acceleration present.

------
nemothekid
> _Another answer I found said no modern operating system will let you access
> the framebuffer directly. BUT LUCKILY THAT’S WRONG._

I don't know why this works for OP, but my understanding is that the original
assertion is true. Writing/Reading directly from fb0 does not work on my
machine.

~~~
karatinversion
Did you try what OP did to fix this for himself – i.e.

> sudo adduser seena video

~~~
nemothekid
No, it's not that I'm having a permission issue - /dev/fb0 simply returns all
0 on my machine.

~~~
therein
I'm getting the following:

    
    
      $ sudo hexdump -C /dev/fb0                                                                                                                                                                                                                                                                                                                                                          
      00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
      *
      0000e000  aa aa aa 00 aa aa aa 00  aa aa aa 00 aa aa aa 00  |................|
      *
      0000e020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
      *
      0000f000  aa aa aa 00 aa aa aa 00  aa aa aa 00 aa aa aa 00  |................|
      *
      0000f020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
      *
      00300000
    

`*` for repeating lines.

------
whalesalad
This is such a cool blog post, and has pulled the covers back on something I
have been curious about for some time.

Makes me wonder why more people aren't abusing this. I can see the gold,
silver and platinum level open source sponsors shoving some big logos down
your throat by writing directly to the framebuffer during your next yarn add.

(I realize it is more nuanced than that, since it requires elevated priviliges
to write to the device ... but hey how many sudo curl bash scripts have you
seen out there in the wild? time to pwn the framebuffer)

~~~
bogwog
You can't write to the framebuffer device while X11 is running because it will
just get overwritten immediately. So that means you can only use it on a
machine without a display server running. So... a web server maybe? Sure, but
since _most_ people use a web server by SSH'ing into it, a program that writes
to framebuffer devices is going to be useless, unless you have a physical
display device connected to the server and want to display something on it
remotely.

So it's mostly a fun gimmick/curiosity. I wrote a realtime 3D rasterizer that
renders to fbdev a while back. It was a fun project, but useless.

~~~
Jasper_
> You can't write to the framebuffer device while X11 is running because it
> will just get overwritten immediately.

You can't write to fbdev because that's not what X11 is using to display
buffers to the screen, it uses the newer kernel mode-setting (KMS) API. It's
only when you switch away to a VT that the "KMS master" drops its session, the
kernel switches back to fbcon, and you can see the "raw fbdev" buffer again,
which is usually a fake framebuffer. If you then write to the fbdev
framebuffer, you'll see your changes, but fbcon will come in and overwrite
them with the kernel console, unless you ioctl(KDSETMODE, KD_GRAPHICS); to
turn off fbcon from drawing.

------
pmorici
If you do use the fb device for some reason you don't need to have the user
give the screen parameters like size and bit depth. Once you know the name of
the framebuffer device all of that information is available in
/sys/class/graphics/fbX/

~~~
Jasper_
There's also FBIOGET_VSCREENINFO / FBIOPUT_VSCREENINFO through which you can
set the current screen information. You can also do fake double buffering this
way, by allocating a mode that's twice as tall, drawing to different parts of
it, and changing the yoffset to present each "buffer".

------
zaptheimpaler
I have so many questions about this stuff! In particular though - im running a
single GPU passthrough setup on my machine. It works smoothly, but I need to
shutdown the display manager (gdm/lightdm etc. depending on distro) before
unbinding the graphics card from the host and assigning it to the guest.

This means when I get back to my host, i have to relogin and all my
windows/apps are gone. There seems to be no way to save/restore the state of
X11 (i know apps themselves wouldn't save state). Is there something
fundamental about how display managers tie into the GPU that makes it
impossible? Is it possible to configure X11 and display managers to use
software rendering only?

------
war1025
In the article it says you can copy `/dev/fb0` to take a screenshot. I tried
this, but I don't know what format that would be to be able to display it or
how to convert it to a usable format. Any ideas?

~~~
X-Cubed
The format used by the framebuffer can differ based on your hardware and your
display settings. You need to use a program that can load raw bitmap data, and
it will need you to tell it what format the source data is in (resolution,
byte order, etc).

There's a good explanation of this on StackOverflow:
[https://stackoverflow.com/questions/1645181/taking-a-
screen-...](https://stackoverflow.com/questions/1645181/taking-a-screen-shot-
of-an-embedded-linux-framebuffer)

------
amelius
Isn't the graphics pipeline a bit more sophisticated nowadays? I.e., you could
render your framebuffer on the side of a rotating cube, let hardware render
fonts, etc.

~~~
kllrnohj
The term "framebuffer" is a bit overloaded here. In this case it means
basically "monitor scan out buffer" and is therefore a very special,
particular thing. In most other contexts 'framebuffer' usually just means your
color output buffer, which is just a buffer of some kind, sitting in some RAM
somewhere, with otherwise no special meaning.

When you setup a swap chain for GUI rendering, for example, you're just doing
a glorified malloc call. It's not coupled to a hardware port. It's not really
even all that special. And then like any other color buffer, you can use that
color buffer in other ways, writing it to yet other color buffers.

All that said the display output pipeline itself still is more sophisticated
than this. Not necessarily by all that much, but it is. Particularly in that
there's not necessarily "one" buffer that drives the monitor. There's this
idea that composition can happen "on the fly" during scan-out by dedicated
hardware, which are done via multiple planes. How many planes can be used then
depends on the hardware, but for example most Android phones have 4-8 hardware
planes. Desktop hardware tends to have fewer such overlay planes (the power
efficiency gains don't tend to matter much when you have infinite power), but
modern Intel integrated GPUs I believe have 3 planes. This is particularly
useful as one of those planes is for video. This means that when you're
watching a video, if things are working properly, then the GPU can be
basically powered off entirely.

------
JosephRedfern
A while back, a bunch of android devices (mainly cheap ones, low end Huaweis
etc) had world readable frame buffers. Meant that an unprivileged app could
read and process /dev/fb0 and snoop on the display. Same was sometimes true
for /dev/input/eventN —- allowed touch screen to be read from and written to.

~~~
stefan_
At some point Samsung flagship phones had world-writable /dev/mem

------
Animats
Direct I/O to the framebuffer may be very, very slow. It usually bypasses all
caches and is treated as a synchronous device register access, which means the
CPU waits for it to complete. And it may be one byte at a time. It's mostly a
legacy mode for debug purposes, boot screens, and such.

------
fabiensanglard
Anybody knows why sudo did not work?

~~~
doublej472
This will only run `cat /dev/urandom` as root, while the redirection is run as
a normal user:

sudo cat /dev/urandom > /dev/fb0

This should work just fine (with a /dev/null redirection so your terminal
doesn't get garbled):

cat /dev/urandom | sudo tee /dev/fb0 > /dev/null

~~~
OskarS
When I encounter this limitation and can not quite remember the correct
incantation to solve it, I usually do something like this in frustration:

    
    
       echo "cat /dev/urandom > /dev/fb0" | sudo sh
    

I was quite proud of myself the first time I figured that out many years ago
:)

~~~
ChristianBundy
Alternatively:

    
    
        sudo sh -c "cat /dev/urandom > /dev/fb0"

------
amelius
How do you select the video mode? (i.e. resolution, refreshrate, bits-per-
pixel, etc.)

~~~
zlynx
[https://stackoverflow.com/questions/34904763/linux-
framebuff...](https://stackoverflow.com/questions/34904763/linux-framebuffer-
set-resolution-correctly)

And [https://www.kernel.org/doc/html/v4.15/gpu/drm-
kms.html](https://www.kernel.org/doc/html/v4.15/gpu/drm-kms.html)

~~~
prashnts
(Not parent) Thanks! I needed this a while back for a bodge. Ended up stashing
it, but this will help a lot!

------
jhoechtl
Welcome to the era of MS-DOS A000:0000 direct video ram drawing frameworks.
And all sorts of tricks of that time using Borland Pascal and Turbo C.

------
jschwartzi
For another fun graphics project try getting Qt5 to compile using the EGL
target on a basic Debian system without using X11 or Wayland/Weston.

------
m00dy
I just remembered Matrix 1 and Neo's framebuffer got hacked during the night
when he got invited to the rave party.

------
rbanffy
I really think it's a shame the framebuffer console can't do proper bold,
italics and underlines...

~~~
Jasper_
fbcon emulates the VT-100. The VT-100 has no support for text formatting,
unfortunately. If a new standard was proposed and you could get acceptance,
similar to some of the other newer protocols like displaying images in the
terminal championed by iTerm, I'm sure Linux would accept a patch for it. I
don't think it's a terrible idea.

~~~
JdeBP
That is after the fact rationalization and wrong.

The "new standard" has existed _since 1976_ , which had boldface, underline,
italics, faint, underline, reverse, concealed, strikethrough, and blinking;
which gained things like overline by the 1980s; and which has been widely
adopted for _over 40 years_.

And the Linux built-in terminal emulator is not emulating a VT100. The idea
that terminal emulators emulate VT100s is generally wrong. Almost always they
are doing what VT100s never did or could do, and conversely often _not_ doing
what DEC VTs did (such as supporting Tektronix, VT52, printers, windowing,
multiple display pages, sixel, locators, ...). The Linux built-in terminal
emulator has several significant differences from a VT10x, not the least of
which is _that it is not monochrome_. The Linux built-in terminal emulator's
closest relative is, rather, the SCO Console.

(Interestingly, SCO's manual relates that the SCO Console actually _did_ have
underline et al., when used on MDA hardware.)

The real problem was that boldface and italics quadruple the kernel font
memory requirements, in a system that is still trying quite hard to limit
itself to 512 glyphs. It's surmountable, but in many respects pointless. The
headlined article is quite apposite, as there exist quite a range of terminal
emulators that run in user space and realize using the frame buffer.

In user space one can be a lot more free with memory, loading multiple fonts
simultaneously for example, and handling the whole of Unicode. And of course
one can implement a whole bunch of the ECMA-48:1976 attributes and colours,
including some of the more recent extensions such as the kitty underlining
variants, AIXterm colours, XTerm colours, and ITU T.416 colours (where "more
recent" for the latter three transalates to "from the 1990s").

~~~
rbanffy
> supporting Tektronix

That'd be awesome, but it'd need to be green, flash bright when drawing and
reverse-flashing the screen on erase. ;-)

> The real problem was that boldface and italics quadruple the kernel font
> memory requirements,

In ancient times we OR'ed a character with itself shifting it one pixel
horizontally. Italics were usually done with shifting the top part of the cell
to the right and the bottom to the left. Some terminals could shift things by
half a pixel, which made for great screen fonts (I did that on Apple IIs).

The same way overlines, underlines and strikethrough are trivial to generate
without adding any glyphs to the font.

~~~
JdeBP
I know.

* [https://github.com/jdebp/nosh/blob/79b1c0aab9834a09a59e15d47...](https://github.com/jdebp/nosh/blob/79b1c0aab9834a09a59e15d47710f355c5c0417a/source/console-fb-realizer.cpp#L818)

But nowadays people expect to provide actual font files for weight and slant
changes, as boldface is not actually overprinting and italics are not oblique.
This starts to matter at cell sizes bigger than 8 by 8, and it isn't an 8 by 8
world nowadays. You'll notice that my terminal emulator reads different font
files for bold/faint/italic combinations if they are given. (On one test
machine I am currently feeding it a combination of UbuntuMono-i and
UbuntuMono-n, with unscii-16-mini and Unifont 7 as fallbacks.)

* [https://github.com/jdebp/nosh/blob/79b1c0aab9834a09a59e15d47...](https://github.com/jdebp/nosh/blob/79b1c0aab9834a09a59e15d47710f355c5c0417a/source/CompositeFont.cpp#L302)

It is not alone. The FreeBSD kernel's newer built-in terminal emulator (vt)
loads two fonts, one for normal (medium) weight and one for boldface.

* [https://github.com/freebsd/freebsd/blob/5f17a06d9cc0a87e26fb...](https://github.com/freebsd/freebsd/blob/5f17a06d9cc0a87e26fbd0e40fe1407847819f17/sys/dev/vt/vt_font.c#L104)

~~~
rbanffy
You still can programatically generate those styles at larger grid sizes. OR
and a single pixel shift will work at 8x8, but if you have enough pixels, you
may need to OR more horizontal and vertical versions to get the effect.

I would prefer better, specifically created font styles (as the good terminals
had), but I'd be totally happy with whatever gave me support for character
styles. I swear that if I could figure out how to add them, I would.

That and smooth scrolling. ;-)

