|
| 1 | +/* |
| 2 | +Framebuffer device /dev/fb0 |
| 3 | +
|
| 4 | +https://en.wikipedia.org/wiki/Linux_framebuffer |
| 5 | +
|
| 6 | +To run this, you must: |
| 7 | +
|
| 8 | +- be on a TTY, e.g. Ctrl + Alt + F2 on Ubuntu |
| 9 | +- add yourself to the `video` group (the group of /dev/fb0 on Ubuntu 16.04) with `sudo usermod -aG video "$USER"`, |
| 10 | + logout and login again , or use sudo |
| 11 | +- have kernel support, I think with `CONFIG_FB=y` and related options. |
| 12 | + http://unix.stackexchange.com/questions/33596/no-framebuffer-device-how-to-enable-it |
| 13 | +
|
| 14 | +Expected outcome: pink square is printed on screen. |
| 15 | +If any terminal text scrolls over it, those square get overwritten. |
| 16 | +Get rid of terminal for good: http://stackoverflow.com/questions/32620019/c-linux-how-to-takeover-the-framebuffer |
| 17 | +
|
| 18 | +Adapted from: |
| 19 | +http://stackoverflow.com/questions/4996777/paint-pixels-to-screen-via-linux-framebuffer |
| 20 | +
|
| 21 | +Other things to try: |
| 22 | +
|
| 23 | + printf 'a\nb' sudo tee /dev/fb0 /dev/null |
| 24 | +
|
| 25 | +Prints text to current cursor position, thus same as stdout. So we see that fb0 can also do text oriented drawing. |
| 26 | +This is different from this program, since here the mmap syscall is used. |
| 27 | +
|
| 28 | +TODO: why a single /dev/fb0 on my laptop? Because a single display? |
| 29 | +
|
| 30 | +Video and images: |
| 31 | +
|
| 32 | +- http://askubuntu.com/questions/46871/how-can-i-play-videos-in-a-framebuffer |
| 33 | +- http://unix.stackexchange.com/questions/226995/how-to-watch-films-images-without-x |
| 34 | +
|
| 35 | +General apps: not possible if they pass through X11: http://unix.stackexchange.com/questions/22757/how-to-run-an-app-in-a-framebuffer |
| 36 | +
|
| 37 | +But SDL 1 notably can render to fbdev. And you could make a GUI in it with AntTweakBar, |
| 38 | +which is a platform agnostic pixel manipulation library. |
| 39 | +But it looks like SDL2 cannot anymore: http://forums.libsdl.org/viewtopic.php?t=9661&sid=47b3f4fde203ea5710a798bb6093b8dd |
| 40 | +
|
| 41 | +Related: |
| 42 | +
|
| 43 | +- http://raspberrypi.stackexchange.com/questions/42628/has-anyone-managed-to-get-sdl-2-3-working-without-x-in-raspbian |
| 44 | +- http://stackoverflow.com/questions/14615732/how-to-get-sdl-to-use-fbcon-not-caca |
| 45 | +- http://stackoverflow.com/questions/26110581/is-there-a-way-to-config-xorg-to-use-a-framebuffer-device-as-the-primary-monitor |
| 46 | +
|
| 47 | +There is the NetSurf browser which is implemented like that: TODO failing in Ubuntu 16.04 with: |
| 48 | +http://askubuntu.com/questions/817937/how-to-run-netsurf-fb-fails-with-unable-to-set-video-could-not-set-console-s |
| 49 | +*/ |
| 50 | + |
| 51 | +#include <stdlib.h> |
| 52 | +#include <unistd.h> |
| 53 | +#include <stdio.h> |
| 54 | +#include <fcntl.h> |
| 55 | +#include <linux/fb.h> |
| 56 | +#include <sys/mman.h> |
| 57 | +#include <sys/ioctl.h> |
| 58 | + |
| 59 | +int main(void) { |
| 60 | + char *fbp = 0; |
| 61 | + int fbfd = 0; |
| 62 | + int x = 0, y = 0; |
| 63 | + long int location = 0; |
| 64 | + long int screensize = 0; |
| 65 | + struct fb_fix_screeninfo finfo; |
| 66 | + struct fb_var_screeninfo vinfo; |
| 67 | + |
| 68 | + /* Open the file for reading and writing */ |
| 69 | + fbfd = open("/dev/fb0", O_RDWR); |
| 70 | + if (fbfd == -1) { |
| 71 | + perror("Error: cannot open framebuffer device"); |
| 72 | + exit(1); |
| 73 | + } |
| 74 | + printf("The framebuffer device was opened successfully.\n"); |
| 75 | + |
| 76 | + /* Get fixed screen information */ |
| 77 | + if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) { |
| 78 | + perror("Error reading fixed information"); |
| 79 | + exit(2); |
| 80 | + } |
| 81 | + |
| 82 | + /* Get variable screen information */ |
| 83 | + if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) { |
| 84 | + perror("Error reading variable information"); |
| 85 | + exit(3); |
| 86 | + } |
| 87 | + |
| 88 | + printf( |
| 89 | + "vinfo.xres = %d\n" |
| 90 | + "vinfo.yres = %d\n" |
| 91 | + "vinfo.bits_per_pixel = %d\n" |
| 92 | + "vinfo.xoffset = %d\n" |
| 93 | + "vinfo.yoffset = %d\n" |
| 94 | + "finfo.line_length = %d\n", |
| 95 | + vinfo.xres, |
| 96 | + vinfo.yres, |
| 97 | + vinfo.bits_per_pixel, |
| 98 | + vinfo.xoffset, |
| 99 | + vinfo.yoffset, |
| 100 | + finfo.line_length |
| 101 | + ); |
| 102 | + |
| 103 | + /* Figure out the size of the screen in bytes */ |
| 104 | + screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; |
| 105 | + |
| 106 | + /* Map the device to memory */ |
| 107 | + fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); |
| 108 | + if (fbp == (void *)-1) { |
| 109 | + perror("Error: failed to map framebuffer device to memory"); |
| 110 | + exit(4); |
| 111 | + } |
| 112 | + |
| 113 | + /* Where we are going to put the pixel */ |
| 114 | + x = 100; y = 100; |
| 115 | + |
| 116 | + /* Figure out where in memory to put the pixel */ |
| 117 | + for (y = 100; y < 300; y++) { |
| 118 | + for (x = 100; x < 300; x++) { |
| 119 | + location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) + |
| 120 | + (y + vinfo.yoffset) * finfo.line_length; |
| 121 | + if (vinfo.bits_per_pixel == 32) { |
| 122 | + /* Blue. */ |
| 123 | + *(fbp + location) = 100; |
| 124 | + /* Green. */ |
| 125 | + *(fbp + location + 1) = 15 + (x - 100) / 2; |
| 126 | + /* Red. */ |
| 127 | + *(fbp + location + 2) = 200 - (y - 100) / 5; |
| 128 | + /* No transparency. */ |
| 129 | + *(fbp + location + 3) = 0; |
| 130 | + //location += 4; |
| 131 | + } else { |
| 132 | + /* assume 16bpp */ |
| 133 | + int b = 10; |
| 134 | + int g = (x - 100) / 6; |
| 135 | + int r = 31 - (y - 100) / 16; |
| 136 | + unsigned short int t = r << 11 | g << 5 | b; |
| 137 | + *((unsigned short int*)(fbp + location)) = t; |
| 138 | + } |
| 139 | + |
| 140 | + } |
| 141 | + } |
| 142 | + munmap(fbp, screensize); |
| 143 | + close(fbfd); |
| 144 | + return 0; |
| 145 | +} |
0 commit comments