tag:blogger.com,1999:blog-50479345688413365762024-03-13T20:09:21.894+00:00Raspberry CompotePseudo-random ramblings about programming and other geeky stuffAnonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.comBlogger29125tag:blogger.com,1999:blog-5047934568841336576.post-54484912445254635972016-03-04T10:41:00.002+00:002016-03-04T10:45:58.921+00:00Low-level Graphics on Raspberry Pi vs other Linux distributions<div style="text-align: justify;">
In the very <a href="http://raspberrycompote.blogspot.com/2012/12/low-level-graphics-on-raspberry-pi-part_9509.html">first post</a> on this subject I suggested the examples would apply to other systems as well - luckily I did add the caveat <i>'some of the code'</i> ;)
</div>
<br/>
<div style="text-align: justify;">
As it appears that the support for the framebuffer driver and the functionality it provides seems to in fact differ a lot between Linux distributions and graphics hardware specific drivers. This was way simpler back in the day I started with Linux fb some 20 years ago... So unfortunately cannot promise the examples will fully work on even another Debian based system. Some of you readers had already found this out some time ago, apologies if it seemed I promised more than I delivered.
</div>
<br/>
<div style="text-align: justify;">
I have recently played with a Debian 8.3.0 distribution on a desktop PC. I found out that for example <a href="http://raspberrycompote.blogspot.com/2013/01/low-level-graphics-on-raspberry-pi-part_22.html">changing the bits_per_pixel</a> does not return errors and querying the information back after setting looks like it went through. But trying to plot pixels will not produce the expected result - it appears that the fb is still in 32 bit mode even when it reports 8 bit :/ Of course any 32 bit pixel plotting code works fine...
</div>
<br/>
<div style="text-align: justify;">
I modified the <a href="https://github.com/rst-/raspberry-compote/blob/6cd23ffa4d6c5909aabccc67e7f5b52e4cdcee27/fb/fbtest.c">original test</a> program <a href="https://github.com/rst-/raspberry-compote/blob/820183a0a0dfe4b942d3ecfa2eedf906bdeb8c2c/fb/fbtest.c">a bit</a> to output some more information. One additional bit (well, a string actually :D ) of information is the <span class="codetoken">fb_fix_screeninfo.id</span> which should give us the fb driver 'name' - for my setup this is <span class="codetoken">inteldrmfb</span>:
<div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-pqEgszgmRLA/VtljFr06avI/AAAAAAAAAOQ/RyO1EV2xIDg/s1600/fbtest.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://1.bp.blogspot.com/-pqEgszgmRLA/VtljFr06avI/AAAAAAAAAOQ/RyO1EV2xIDg/s320/fbtest.png" /></a></div>
</div>
<br/>
<div style="text-align: justify;">
The 'drm' part there suggests that the driver is implementing the more recent <a href="https://en.wikipedia.org/wiki/Direct_Rendering_Manager">Direct Rendering Manager (DRM)</a> model and the <a href="https://en.wikipedia.org/wiki/Linux_framebuffer">fbdev</a> support is not complete. If running other distributions and interested in low level graphics it would be worth investigation the DRM API <i>libdrm</i>.
</div>
<br/>
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-41743211731432048182016-02-24T16:40:00.000+00:002016-02-25T10:45:14.339+00:00Low-level Graphics on Raspberry Pi (more images)<div style="text-align: justify;">
In an earlier <a href="http://raspberrycompote.blogspot.ie/2016/01/low-level-graphics-on-raspberry-pi.html">post</a> we looked at converting an image to 16 bit 5:6:5 format for direct copying to framebuffer. The obvious drawback of that approach is the requirement on the image size to exactly match the display/framebuffer size (or the width at least).
</div>
<br/>
<div style="text-align: justify;">
Modifying the PPM reading code to read into an image object in memory (I chose to use the <span class="codetoken">struct fb_image</span> from <span class="codetoken">linux/fb.h</span> as teh image object) and combining that with the familiar framebuffer drawing code (<span class="codetoken">put_pixel_RGB565</span> from <a href="http://raspberrycompote.blogspot./2013/03/low-level-graphics-on-raspberry-pi-part_8.html">part 6</a>)
<div class="code">
<pre>
...
int read_ppm(char *fpath, struct fb_image *image) {
...
image->data = malloc(width * height * bytes_per_pixel);
...
// store pixel in memory
unsigned int pix_offset = (y * width + x ) * bytes_per_pixel;
*((unsigned short *)(image->data + pix_offset)) = rgb565;
...
void draw(struct fb_image *image) {
int y;
int x;
unsigned char rgb[3];
for (y = 0; y < image->height; y++) {
for (x = 0; x < image->width; x++) {
// get pixel from image
unsigned int img_pix_offset = (y * image->width + x) * 2;
unsigned short c =
*(unsigned short *)(image->data + img_pix_offset);
// plot pixel to screen
unsigned int fb_pix_offset =
x * 2 + y * finfo.line_length;
*((unsigned short*)(fbp + fb_pix_offset)) = c;
}
}
}
...
int main(int argc, char* argv[])
{
// read the image file
int ret = read_ppm(argv[1], &image);
if (ret != 0) {
printf("Reading image failed.\n");
return ret;
}
...
</pre>
</div>
Make sure you have a 24 bit PPM image file to start with - convert one from for example PNG using <span class="codetoken">pngtopnm</span> (any bit depth source file should do) - and make sure the image fits the screen (no bounds checking in the code). Then compile and run:
<div class="output">
<pre>
gcc -O2 -o ppmtofbimg ppmtofbimg.c
./ppmtofbimg test24.ppm
</pre>
</div>
<div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-_5dcN3Tw3AY/Vs3cuuLswgI/AAAAAAAAAOA/hmB2A4HWRg8/s1600/ppmtofbimg.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://4.bp.blogspot.com/-_5dcN3Tw3AY/Vs3cuuLswgI/AAAAAAAAAOA/hmB2A4HWRg8/s320/ppmtofbimg.png" /></a></div>
</div>
<div style="text-align: justify;">
Full source and a test image (test24.ppm) in <a href="https://github.com/rst-/raspberry-compote/tree/master/img">GitHub</a>.
</div>
<br/>
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-56002519585174298562016-02-23T11:36:00.001+00:002016-02-23T11:39:34.766+00:00Modifying Ctrl+Alt+Del behavior in Debian Jessie vs Wheezy<div style="text-align: justify;">
Finally got up to testing Raspbian <a href="https://www.raspberrypi.org/blog/raspbian-jessie-is-here/">Jessie</a> and being a mixed user of Linux and Windows ran into an issue with the 'three finger salute' <span class="codetoken">Ctrl-Alt-Del</span> (C-D-A) key combination. In Windows this is normally used to lock up the UI when going away from the computer and often comes automatically 'from the spine'. In Linux it nowadays seems to normally initiates a reboot ...in the windowing systems this usually pops up a dialog asking to confirm but when working in the console only it just reboots. Which is of course fairly annoying when not intentional :|
</div>
<br/>
<div style="text-align: justify;">
The previous release of Raspbian - based on Debian <a href="https://www.debian.org/releases/wheezy/">Wheezy</a> - is built on the <a href="https://en.wikipedia.org/wiki/Init#SysV-style">sysvinit</a> style boot and the <span class="codetoken">Ctrl-Alt-Del</span> behavior is defined in the <span class="codetoken">/etc/inittab</span> file and can be disabled by commenting out the line that looks something like:
<div class="output">
<pre>
...
# What to do when CTRL-ALT-DEL is pressed.
ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now
...
</pre>
</div>
So:
<div class="output">
<pre>
sudo nano /etc/inittab
*** find the line with 'ctrlaltdel' (Ctrl-W for search)
*** comment out by adding the hash '#' at beginning of line
*** save file (Ctrl-O) and exit (Ctrl-X)
sudo init q
</pre>
</div>
...the last command 're-reads' the inittab file and applies the change.
</div>
<br/>
<div style="text-align: justify;">
But <a href="https://www.debian.org/releases/jessie/">Jessie</a> is built on the <a href="https://en.wikipedia.org/wiki/Systemd">systemd</a> style boot and there is no more <span class="codetoken">/etc/inittab</span>. Surprisingly I did not find a clear, full answer to this using Google - some links like <a href="https://www.debian.org/doc/manuals/securing-debian-howto/ch4.en.html">Securing Debian Manual</a> (4.8 Restricting system reboots through the consol) are outdated for Jessie - <a href="https://lists.debian.org/debian-user/2015/11/msg01285.html">some</a> are unanswered - <a href="https://lists.debian.org/debian-user/2015/12/msg00048.html">some</a> only offer partial information - and <a href="https://groups.google.com/forum/#!topic/linux.debian.user/3sk6E_soSdc">some</a> discuss slightly different variation of behavior wanted. Combining the information from those it appears the behavior is controlled by <span class="codetoken">/lib/systemd/system/ctrl-alt-del.target</span> (not /etc/systemd/system/*):
<div class="output">
<pre>
ls -la /lib/systemd/system/ctrl*
lrwxrwxrwx 1 root root 13 Aug 30 23:04 /lib/systemd/system/ctrl-alt-del.target -> reboot.target
</pre>
</div>
To change this we need to remove the current link and replace:
<div class="output">
<pre>
sudo rm /lib/systemd/system/ctrl-alt-del.target
sudo ln -s /dev/null /lib/systemd/system/ctrl-alt-del.target
sudo systemctl daemon-reload
</pre>
</div>
...so to disable <span class="codetoken">Ctrl-Alt-Del</span> we point the target to <span class="codetoken">/dev/null</span> i.e. to be completely ignored and again the last command 're-reads' the configuration and applies the change.
</div>
<br/>
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-11651684800677864362016-02-11T12:03:00.000+00:002016-02-11T12:37:17.394+00:00Low-level Graphics on Raspberry Pi (even more palette)<div style="text-align: justify;">
Another effect with palette: fade in/out. We can - in addition to <a href="http://raspberrycompote.blogspot.com/2016/02/low-level-graphics-on-raspberry-pi-more.html">rotating the entries</a> - modify the palette entry RGB values on the fly and make the pixels drawn in this color to fade in or out.
</div>
<br/>
<div style="text-align: justify;">
Draw some background stuff (blue and white checkerboard), a black block to hold the actual piece and something to fade:
<div class="code">
<pre>
...
#define DEF_COLOR 14
#define MOD_COLOR (16 + DEF_COLOR)
...
int x, y;
int t = vinfo.xres / 24;
// t x t pix black and white checkerboard
for (y = 0; y < vinfo.yres; y++) {
int xoffset = y / t % 2;
for (x = 0; x < vinfo.xres; x++) {
// color based on the tile
int c = (((x / t + xoffset) % 2) == 0) ? 1 : 15;
// draw pixel
put_pixel(x, y, c);
}
}
// black block in the middle
for (y = (vinfo.yres / 2); y < (vinfo.yres / 2 + t); y++) {
for (x = (vinfo.xres / 4 - t / 2);
x < (vinfo.xres / 4 * 3 + t / 2); x++)
{
put_pixel(x, y, 0);
}
}
// something in the color in the extended palette
for (y = (vinfo.yres / 2 + t / 4);
y < (vinfo.yres / 2 + t - t / 4); y++)
{
int n = 0;
for (x = (vinfo.xres / 4); x < (vinfo.xres / 4 * 3); x++) {
if (n % (t / 4)) {
put_pixel(x, y, MOD_COLOR);
}
n++;
}
}
...
</pre>
</div>
And then modify the associated palette entry:
<div class="code">
<pre>
...
// fade palette entry out (to black)" and back in
int j;
int fps = 60; // frames per second
int f = 255;
int fd = -2;
while (f < 256) {
r[DEF_COLOR] = (def_r[14] & f) << 8;
g[DEF_COLOR] = (def_g[14] & f) << 8;
b[DEF_COLOR] = (def_b[14] & f) << 8;
// change fade
f += fd;
// check bounds
if (f < 0) {
// change direction
fd *= -1;
f += fd;
}
// Note that we set up the 'pal' structure earlier
// and it still points to the r, g, b arrays,
// so we can just reuse 'pal' here
if (ioctl(fbfd, FBIOPUTCMAP, &pal) != 0) {
printf("Error setting palette.\n");
}
usleep(1000000 / fps);
}
...
</pre>
</div>
Compile with <span class="codetoken">'gcc -o fbtest5z fbtest5z.c'</span> and run with <span class="codetoken">'./fbtest5y'</span>. The yellow bars should fade out and back in:
<div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-JtOeRXHUYH4/Vrx4ES1QzKI/AAAAAAAAANk/LT2VyvzK8W8/s1600/fbtest5z.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://1.bp.blogspot.com/-JtOeRXHUYH4/Vrx4ES1QzKI/AAAAAAAAANk/LT2VyvzK8W8/s320/fbtest5z.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-rBj86zMKNCc/Vrx4ERmrpLI/AAAAAAAAANo/XFBvIsSnHwk/s1600/fbtest5zb.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://4.bp.blogspot.com/-rBj86zMKNCc/Vrx4ERmrpLI/AAAAAAAAANo/XFBvIsSnHwk/s320/fbtest5zb.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-GeltetWSqXc/Vrx4bi37NvI/AAAAAAAAANs/x4nYvjBuAfg/s1600/fbtest5zc.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://4.bp.blogspot.com/-GeltetWSqXc/Vrx4bi37NvI/AAAAAAAAANs/x4nYvjBuAfg/s320/fbtest5zc.png" /></a></div>
...imagine for example black background and white text fading in and out... movie titles :D
</div>
<br/>
<div style="text-align: justify;">
Full code available in <a href="https://github.com/rst-/raspberry-compote/blob/master/fb/fbtest5z.c">GitHub</a>.
</div>Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-33575189288201046762016-02-10T14:33:00.002+00:002016-02-16T10:57:26.328+00:00Low-level Graphics on Raspberry Pi (more palette)<div style="text-align: justify;">
In a previous <a href="http://raspberrycompote.blogspot.ie/2015/12/low-level-graphics-on-raspberry-pi-part.html">post</a> we briefly looked at palette animation. Now (hopefully) a slightly more appetising example of what could be done with this technique.
</div>
<br/>
<div style="text-align: justify;">
Let's draw some 'rainbow striped' blocks and customise the palette to include 16 colors sliding from red to yellow:
<div class="code">
<pre>
...
void draw() {
...
// colored blocks
for (y = 0; y < vinfo.yres; y += t) {
int xoffset = y / t % 2;
for (x = t * xoffset; x < vinfo.xres; x += t * 2) {
int x2, y2;
for (y2 = 0; y2 < t; y2++) {
for (x2 = 0; x2 < t; x2++) {
// color based on y2 value
// using the custom colors (16+)
int c = 16 + (y2 % 16);
// draw pixel
put_pixel(x + x2, y + y2, c);
}
}
}
}
}
...
int main(int argc, char* argv[])
{
...
// Set palette
...
for(i = 0; i < 16; i++) {
// red-yellow gradient
// note that Linux provides more precision (0-65535),
// so we multiply ours (0-255) by 256
r[i] = 255 << 8;
g[i] = ((15 - i) * 16) << 8;
b[i] = 0;
}
...
</pre>
</div>
And then animate the palette by rotating the custom color entries:
<div class="code">
<pre>
...
int j;
int fps = 30; // frames per second
int d = 5; // duration in seconds
// repeat for given time
for(j = 0; j < fps * d; j++) {
// store color 0 in temp variables
int rt = r[0];
int gt = g[0];
int bt = b[0];
// replace colors by copying the next
for(i = 0; i < 15; i++) {
r[i] = r[i+1];
g[i] = g[i+1];
b[i] = b[i+1];
}
// restore last one from temp
r[15] = rt;
g[15] = gt;
b[15] = bt;
// Note that we set up the 'pal' structure earlier
// and it still points to the r, g, b arrays,
// so we can just reuse 'pal' here
if (ioctl(fbfd, FBIOPUTCMAP, &pal) != 0) {
printf("Error setting palette.\n");
}
usleep(1000000 / fps);
}
...
</pre>
</div>
Compile with <span class="codetoken">'gcc -o fbtest5y fbtest5y.c'</span> and run with <span class="codetoken">'./fbtest5y'</span>. The blue checker board with holes looks like floating on top of flowing lava waves ;)
<div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-JVHkS9ESLzg/Vrx0WiOVqEI/AAAAAAAAANM/krrQztFs5q8/s1600/fbtest5y.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://4.bp.blogspot.com/-JVHkS9ESLzg/Vrx0WiOVqEI/AAAAAAAAANM/krrQztFs5q8/s320/fbtest5y.png" /></a></div>
</div>
<br/>
<div style="text-align: justify;">
Full code available in <a href="https://github.com/rst-/raspberry-compote/blob/master/fb/fbtest5y.c">GitHub</a>.
</div>
<br />
<div style="text-align: justify;">
[Continued in next part <a href="http://raspberrycompote.blogspot.com/2016/02/low-level-graphics-on-raspberry-pi-even.html">Even more palette</a>]
</div>
<br />
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-59951453019042575822016-01-27T13:04:00.001+00:002016-02-24T15:30:51.550+00:00Low-level Graphics on Raspberry Pi (images)<div style="text-align: justify;">
One of the recurring <a href="https://www.raspberrypi.org/forums/viewtopic.php?f=32&t=57810">themes</a> regarding Raspberry Pi graphics is the 16-bit RGB 5:6:5 display mode vs typically 24-bit images. The '565' mode is the default on HDMI and possibly the only one available on TFT add-on displays like this <a href="https://www.adafruit.com/products/1601">one from Adafruit</a>.
</div>
<br/>
<div style="text-align: justify;">
There are tools that can be used to display images in the framebuffer - which do a suitable color-space conversion and do seem to work with the '565' display mode. However for simple and speedy display of images it would in many cases be useful to be able to convert the image to '565' beforehand. The usual suspect tools <a href="http://netpbm.sourceforge.net/">Netpbm</a> and <a href="http://www.imagemagick.org/">Imagemagick</a> do not seem to include an option to convert to '565'. Only tool I know for sure has this is <a href="https://www.gimp.org/">GIMP </a> which is a fairly big interactive GUI application and might not suit (there is some level of scripting support though which might be worth checking out). As a side note <a href="http://www.irfanview.com/">IrfanView </a>for Windows can read '565' raw images fine (but does not seem to have an option to save in this mode).
</div>
<br/>
<div style="text-align: justify;">
Fellow RPi forum user <i>bullwinkle</i> has <a href="https://www.raspberrypi.org/forums/viewtopic.php?f=32&t=57810#p892279">found out</a> that <a href="https://www.ffmpeg.org/">ffmpeg</a> supports this mode and - while more typically used for stitching together images to form a video - can also output image files:
<div class="output">
<pre>
ffmpeg -vcodec png -i input.png -vcodec rawvideo -f rawvideo \
-pix_fmt rgb565 output.raw
</pre>
</div>
</div>
<br/>
<div style="text-align: justify;">
I created a simple 'quick and dirty' <a href="https://github.com/rst-/raspberry-compote/blob/master/img/ppmtorgb565.c">conversion program</a> for converting a 24-bit PPM image file to 16-bit 'raw' RGB 565 format. The colorspace conversion is fairly simple: take the top 5 bytes of 8-bit red value <span class="codetoken">r >> 3</span> (bitwise shift right, 8 - 5 = 3), top 6 of green, top 5 of blue - and stitch back together into one 16-bit RGB <span class="codetoken">rgb = (r << 11) + (g << 5) + b</span>:
<div class="code">
<pre>
...
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
if (fread(rgb, 3, 1, fp) == 1) {
unsigned char r = rgb[0];
unsigned char g = rgb[1];
unsigned char b = rgb[2];
unsigned short rgb565 = ((r >> 3) << 11) +
((g >> 2) << 5) +
(b >> 3);
unsigned char c1 = (rgb565 & 0xFF00) >> 8;
unsigned char c2 = (rgb565 & 0xFF);
fwrite(&c2, 1, 1, stdout);
fwrite(&c1, 1, 1, stdout);
}
...
</pre>
</div>
Compile with:
<div class="output">
<pre>
gcc -O2 -o ppmtorgb565 ppmtorgb565.c
</pre>
</div>
And starting off with a 24-bit PNG file use <span class="codetoken">pngtoppm</span> from the Netpbm package to convert PNG->PPM, pipe the output to the new tool and save the final output to a file:
<div class="output">
<pre>
pngtopnm /path/to/image24.png | /path/to/ppmtorgb565 > image565.raw
</pre>
</div>
Or maybe even direct to framebuffer (if 'disk' space is more valuable than run speed):
<div class="output">
<pre>
pngtopnm /path/to/image24.png | /path/to/ppmtorgb565 > /dev/fb1
</pre>
</div>
...as (almost) everything in Linux is a file ;)
</div>
<br/>
<div style="text-align: justify;">
<strike>Disclaimer: I have not yet tested this on RPi - just on a PC running a Debian VM - will update after properly testing (or seeing comments on the RPi forum in the aforementioned thread)</strike>. This has now been succesfully tested on RPi. My test images can be found in <a href="https://github.com/rst-/raspberry-compote/tree/master/img">GitHub</a> too (along a PPM to 24-bit RGB '888' converter).
</div>
<br />
<div style="text-align: justify;">
[Continued in next part <a href="http://raspberrycompote.blogspot.com/2016/02/low-level-graphics-on-raspberry-pi-more.html">More palette</a>]
</div>
<br />
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-54157941855087184072015-12-03T14:36:00.001+00:002016-02-16T10:53:32.349+00:00 Low-level Graphics on Raspberry Pi (palette)<div style="text-align: justify;">
Again life has happened and the time has slipped. Thanks for the response on the Raspberry Pi forum. To iterate the message from there: I have disabled comments here because I cannot guarantee any kind of decent response time, sorry.
</div>
<br/>
<div style="text-align: justify;">
Just a quick, short one now on something I came across trawling through old stuff. <i>Palette animation</i> a.k.a <i>color cycling</i> (<a href="https://en.wikipedia.org/wiki/Color_cycling">Wikipedia</a>) is a technique that might produce interesting effects when applied to a suitably arranged image. In most cases it is likely to be a lot faster than redrawing the actual pixels. Continuing from the <span class="codetoken">fbtest5.c</span> introduced in <a href=http://raspberrycompote.blogspot.com/2013/03/low-level-graphics-on-raspberry-pi-part_7.html>Part V</a> we can animate the palette like this:
<div class="code">
<pre>
// draw...
draw();
sleep(1);
int j;
for(j = 0; j < 16; j++) {
for(i = 0; i < 16; i++) {
// rotate the original values based on j changing...
r[i] = def_r[(i + j + 1) % 16] << 8;
g[i] = def_g[(i + j + 1) % 16] << 8;
b[i] = def_b[(i + j + 1) % 16] << 8;
}
// Note that we set up the 'pal' structure earlier
// and it still points to the r, g, b arrays,
// so we can just reuse 'pal' here
if (ioctl(fbfd, FBIOPUTCMAP, &pal)) {
printf("Error setting palette.\n");
}
sleep(1);
}
</pre>
</div>
...which should cycle the color bars in the lower half of the screen.
<div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-n1l1WhNWDqY/Vrx1iAw_xGI/AAAAAAAAANY/mm1jz8lMXWw/s1600/fbtest5x.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://4.bp.blogspot.com/-n1l1WhNWDqY/Vrx1iAw_xGI/AAAAAAAAANY/mm1jz8lMXWw/s320/fbtest5x.gif" /></a></div>
<br/>
[Full source available in <a href="https://github.com/rst-/raspberry-compote/blob/master/fb/fbtest5x.c">GitHub</a>]
</div>
<br />
<div style="text-align: justify;">
[Continued in next part <a href="http://raspberrycompote.blogspot.com/2016/01/low-level-graphics-on-raspberry-pi.html">Images</a>]
</div>
<br />Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-87684022013875541392015-01-27T14:29:00.000+00:002015-01-27T16:36:00.659+00:00Low-level Graphics on Raspberry Pi (part X update III)<div style="text-align: justify;">
Finally managed to find the cause for the (intermittent - reproducible at will only straight after boot) screen blanking issue (mentioned in previous <a href="http://raspberrycompote.blogspot.com/2015/01/low-level-graphics-on-raspberry-pi-part.html">post</a>): the changes in the framebuffer driver seem to require the calls to KDSETMODE to be inside the FBIOPUT_VSCREENINFO calls... Fixed code now in <a href="https://github.com/rst-/raspberry-compote/blob/master/fb/fbtestXIV.c">GitHub</a>
</div>Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-80642536861153611162015-01-06T16:46:00.003+00:002015-01-27T16:36:29.063+00:00Low-level Graphics on Raspberry Pi (part X update II)<div style="text-align: justify;">
Finally... in continuation to this <a href="http://raspberrycompote.blogspot.com/2014/09/low-level-graphics-on-raspberry-pi-part.html">post</a>, after some elaboration on the <a href="http://www.raspberrypi.org/forums/viewtopic.php?f=67&t=19073&p=666616#p665518">forum</a> I managed to get down to testing this properly - it appears that the changes in the fb driver can be made to work! Replace the 'switch page' by either (ioctl version):
<div class="code">
<pre>
// switch page
// ioctl version
vinfo.yoffset = cur_page * vinfo.yres;
ioctl(fbfd, FBIOPAN_DISPLAY, &vinfo);
ioctl(fbfd, FBIO_WAITFORVSYNC, 0);
</pre>
</div>
or (mailbox version):
<div class="code">
<pre>
// switch page
// mailbox version
vx = 0;
vy = cur_page * vinfo.yres;
set_fb_voffs(&vx, &vy);
ioctl(fbfd, FBIO_WAITFORVSYNC, 0);
</pre>
</div>
Curiously the order has to be pan first - wait for vsync after... Obviously if going for the 'ioctl only version' one can scrap all the extra code and there is no need to create the char_dev node etc.
</div>
<div style="text-align: justify;">
<br />
Cleaned up 'pure Linux fb' version of the code available in <a href="https://github.com/rst-/raspberry-compote/blob/master/fb/fbtestXIV.c">GitHub</a>. Compile with (as I took out the timing code no need for the <span style="codetoken">rt</span> lib):
<div class="output">
<pre>
gcc -O2 -o fbtestXIV fbtestXIV.c
</pre>
</div>
And run with:
<div class="output">
<pre>
fbset -depth 8
./fbtestXIV
</pre>
</div>
...as it appears the latest Raspbian builds require forcing the framebuffer mode to 8-bit colors before running the examples where 8-bit mode is set. Later the mode can be freely set and the examples run fine...
If you want to time the execution use:
<div class="output">
<pre>
time ./fbtestXIV
</pre>
</div>
...which should give just over 10 s if we managed to produce 60 fps for 10 seconds.
</div>
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com1tag:blogger.com,1999:blog-5047934568841336576.post-68421334285011910612014-09-04T22:41:00.000+01:002015-01-27T16:36:17.943+00:00Low-level Graphics on Raspberry Pi (part X update)<div style="text-align: justify;">
BREAKING NEWS: The Raspberry Pi Linux framebuffer <a href="https://github.com/raspberrypi/linux/blob/rpi-3.12.y/drivers/video/bcm2708_fb.c">driver</a> has been updated and the PAN_DISPLAY function mentioned in <a href="http://raspberrycompote.blogspot.com/2014/03/low-level-graphics-on-raspberry-pi-part_14.html">Part X</a> has been added - so the smooth double-buffer page-flipping animation should now be possible without further hacks!
</div>
<br/>
<div style="text-align: justify;">
Based on a quick test it works fine - will get back with a confirmation after some more testing...
</div>
<br/>
<div style="text-align: justify;">
UPDATE 2014-09-10: Well, the pan (and set virtual info) now work fine but it appears that the vsync functionality does not. Also it looks like there was a change made somewhere deeper in the software stack and the mailbox interface based version does not have the vsync anymore either.
</div>
<br/>
<div style="text-align: justify;">
UPDATE 2015-01-06: new <a href="http://raspberrycompote.blogspot.com/2015/01/low-level-graphics-on-raspberry-pi-part.html">info</a>
</div>
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-40147329021345369262014-04-18T18:34:00.001+01:002016-02-24T15:31:14.308+00:00Low-level Graphics on Raspberry Pi (text)<div style="text-align: justify;">
Someone asked me how to go about rendering text - as we are using a framebuffer in graphics mode and can only plot pixels, text output does not come for free and has to be done extending the pixel plotting.
</div>
<br />
<div style="text-align: justify;">
There are basically two different ways to render text: <a href="http://en.wikipedia.org/wiki/Computer_font">raster fonts and vector fonts</a>. A font is a collection of character representations or 'images' of characters (letters and symbols). As should be obvious: raster font represents the characters as raster images - vector font represents them as collections of lines/polygons. Using the utility functions presented in previous posts, it would be possible to choose either approach.
</div>
<br />
<div style="text-align: justify;">
Let's take a look at simple <a href="http://en.wikipedia.org/wiki/Monospaced_font">monospace</a> raster fonts. Each character would be a block of pixels: some filled - some empty. For example a simple version of the letter 'A' as a 8x8 pixel image could be:
<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/-SgOl4ZxX64M/U1E_dQTr8II/AAAAAAAAAJ4/UZiDJ01W248/s1600/pixfontA.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-SgOl4ZxX64M/U1E_dQTr8II/AAAAAAAAAJ4/UZiDJ01W248/s320/pixfontA.png" /></a></div>
...the image occupies 64 pixels: 8 across and 8 down - the pixels representing the character outline would be filled (in this case black). A naive implementation could just plot the pixels:
<div class="code">
<pre>
void draw_char(char a, int x, int y, int c) {
switch (a) {
case 'A':
// top row
put_pixel(x + 3, y, c);
put_pixel(x + 4, y, c);
// next row
put_pixel(x + 2, y, c);
put_pixel(x + 5, y, c);
...
}
</pre>
</div>
...which obviously would not be very efficient coding wise.
</div>
<br />
<div style="text-align: justify;">
A better solution would be to use a pixel map - a raster image - and copy this image to the desired spot on the screen. The pixel map could be drawn in a drawing program like <a href="http://www.gimp.org/">GIMP</a>, saved to a file, loaded into memory in our program and the character pixel blocks copied from it to the screen. This might be the best way to go, but dealing with image file formats is another story... Alternative way would be to define the pixel maps in code - something along:
<div class="code">
<pre>
char A[] = {
0, 0, 0, 1, 1, 0, 0, 0,
0, 0, 1, 0, 0, 1, 0, 0,
0, 1, 0, 0, 0, 0, 1, 0,
0, 1, 0, 0, 0, 0, 1, 0,
0, 1, 1, 1, 1, 1, 1, 0,
0, 1, 0, 0, 0, 0, 1, 0,
0, 1, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
</pre>
</div>
Now how to avoid the long switch statement... Typically computer systems would use a character encoding scheme like <a href="http://en.wikipedia.org/wiki/ASCII">ASCII</A>, which in fact is used by the C language in Linux by default. The scheme defines numerical codes for characters: for example space character is 32 (decimal) and the exclamation mark 33 - a quick test to see this in effect would be:
<div class="code">
<pre>
printf("%c", 33);
printf("\n");
printf("%d", ' ');
</pre>
</div>
...which should print out the exclamation mark and number 32. As this is pretty much a standard and, if leaving out the first 32 non-printable control characters, quite convenient for our purpose, we could define all character pixel maps in one two dimensional array:
<div class="code">
<pre>
#define FONTW 8
#define FONTH 8
char fontImg[][FONTW * FONTH] = {
{ // ' ' (space)
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
},
{ // !
0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
},
...
}
</pre>
</div>
...where the outer array size is left to be decided (by the compiler) based on the actual entries defined, so we can do some of the first characters for testing and leave rest for later.
</div>
<br />
<div style="text-align: justify;">
So we have the characters defined in the ASCII order, but leaving out the first 32 and we can get the appropriate pixel map using the C language <span class="codetoken">char</span>/<span class="codetoken">integer</span> interchangeability:
<div class="code">
<pre>
char c = '!';
char *img = fontImg[c - 32];
</pre>
</div>
...now the <span class="codetoken">imgc</span> variable would point to the 8x8 bytes pixel map for the exclamation mark.
</div>
<br />
<div style="text-align: justify;">
Drawing a single character using the <span class="codetoken">put_pixel</span> function familiar form before could be implemented as:
<div class="code">
<pre>
// loop through pixel rows
for (y = 0; y < FONTH; y++) {
// loop through pixel columns
for (x = 0; x < FONTW; x++) {
// get the pixel value
char b = img[y * FONTW + x];
if (b > 0) { // plot the pixel
put_pixel(textX + i * FONTW + x, textY + y,
textC);
}
else {
// leave empty (or maybe plot 'text backgr color')
}
} // end "for x"
} // end "for y"
</pre>
</div>
And drawing a string (an array of characters):
<div class="code">
<pre>
// loop through all characters in the text string
l = strlen(text);
for (i = 0; i < l; i++) {
// get the 'image' index for this character
int ix = font_index(text[i]);
// get the font 'image'
char *img = fontImg[ix];
// loop through pixel rows
...
} // end "for y"
} // end "for i"
</pre>
</div>
Putting all this together with setting up the graphics mode etc (full code in <a href="https://github.com/rst-/raspberry-compote/tree/master/fb/font">GitHub</a> - note the .c and .h both required), compiling with <span class="codetoken">gcc -o fbtestfnt fbtestfnt.c</span> and running with a command like:
<div class="output">
<pre>
$ ./fbtestfnt "A\"BC\"D'E'F,.;:012(8)9+-<=>?"
</pre>
</div>
...should give us a display similar to:
<div class="separator" style="clear: both; text-align: center;"><a href="http://2.bp.blogspot.com/-Nu33AqWYQe8/U1FWx9oEPrI/AAAAAAAAAKI/17XnrgqalDo/s1600/fbgrab.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-Nu33AqWYQe8/U1FWx9oEPrI/AAAAAAAAAKI/17XnrgqalDo/s320/fbgrab.png" /></a></div>
As one can see, the .h file contains only part of the full character set - rest are left as an exercise for the reader ;) Also obviously the 8x8 pixel font is quite small for higher resolutions - the code should provide for easy customisation to support more character sizes and/or multi-colored (possibly anti-aliased) fonts ...or to get creative with additional characters (127+ indexes '<a href="http://asciiset.com/">extended ASCII</a>' or maybe <a href="http://en.wikipedia.org/wiki/PETSCII">PETSCII</a> ...or Easter eggs :P ).
</div>
<br />
<div style="text-align: justify;">
[Continued in next part <a href="http://raspberrycompote.blogspot.com/2015/12/low-level-graphics-on-raspberry-pi-part.html">Palette</a>]
</div>
<br />Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-51589274975017000062014-04-10T15:34:00.001+01:002016-02-24T15:31:25.690+00:00Low-level Graphics on Raspberry Pi (shapes)<div style="text-align: justify;">
By now (this was started a year ago already) I would assume most of the most interested readers having developed their own drawing functions for creating more useful output. But just in case there are newcomers or someone needs a push to the right direction... Let's take a look at drawing some basic shapes.
</div>
<br />
<div style="text-align: justify;">
In <a href=http://raspberrycompote.blogspot.com/2013/04/low-level-graphics-on-raspberry-pi-part_3.html>part eight</a> we drew some vertical and horizontal lines by repeating calls to <span class="codetoken">put_pixel</span> for adjacent pixels. How about sloping lines? Not so trivial (except exactly 1:1 slope) - as one pixel step in one direction may need multiple pixels step in the other direction and normally gaps would not be wanted. Luckily this has been studied decades ago and there exists a well known <a href=http://en.wikipedia.org/wiki/Algorithm>algorithm</a> for drawing sloping lines called the <a href=http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm>Bresenham's line algorithm</a> which in our case can be implemented as:
<div class="code">
<pre>
void draw_line(int x0, int y0, int x1, int y1, int c) {
int dx = x1 - x0;
dx = (dx >= 0) ? dx : -dx; // abs()
int dy = y1 - y0;
dy = (dy >= 0) ? dy : -dy; // abs()
int sx;
int sy;
if (x0 < x1)
sx = 1;
else
sx = -1;
if (y0 < y1)
sy = 1;
else
sy = -1;
int err = dx - dy;
int e2;
int done = 0;
while (!done) {
put_pixel(x0, y0, c);
if ((x0 == x1) && (y0 == y1))
done = 1;
else {
e2 = 2 * err;
if (e2 > -dy) {
err = err - dy;
x0 = x0 + sx;
}
if (e2 < dx) {
err = err + dx;
y0 = y0 + sy;
}
}
}
}
</pre>
</div>
...which should work for any line orientations.
</div>
<br />
<div style="text-align: justify;">
Drawing other shapes becomes a lot easier using the line function - like rectangle outline:
<div class="code">
<pre>
// (x0, y0) = left top corner coordinates
// w = width and h = height
void draw_rect(int x0, int y0, int w, int h, int c) {
draw_line(x0, y0, x0 + w, y0, c); // top
draw_line(x0, y0, x0, y0 + h, c); // left
draw_line(x0, y0 + h, x0 + w, y0 + h, c); // bottom
draw_line(x0 + w, y0, x0 + w, y0 + h, c); // right
}
</pre>
</div>
Even filling a rectangle can be implemented using the same:
<div class="code">
<pre>
void fill_rect(int x0, int y0, int w, int h, int c) {
int y;
for (y = 0; y < h; y++) {
draw_line(x0, y0 + y, x0 + w, y0 + y, c);
}
}
</pre>
</div>
...for each line/y we draw a horizontal line... Of course it might be a good idea to optimize this using <a href=http://linux.die.net/man/3/memset>memset()</a>...
</div>
<br />
<div style="text-align: justify;">
The Bresenham's line algorithm has been extended to draw circles as well - this is very clever optimisation only calculating the points for one eight of the circle and just mirroring the rest:
<div class="code">
<pre>
void draw_circle(int x0, int y0, int r, int c)
{
int x = r;
int y = 0;
int radiusError = 1 - x;
while(x >= y)
{
// top left
put_pixel(-y + x0, -x + y0, c);
// top right
put_pixel(y + x0, -x + y0, c);
// upper middle left
put_pixel(-x + x0, -y + y0, c);
// upper middle right
put_pixel(x + x0, -y + y0, c);
// lower middle left
put_pixel(-x + x0, y + y0, c);
// lower middle right
put_pixel(x + x0, y + y0, c);
// bottom left
put_pixel(-y + x0, x + y0, c);
// bottom right
put_pixel(y + x0, x + y0, c);
y++;
if (radiusError < 0)
{
radiusError += 2 * y + 1;
} else {
x--;
radiusError+= 2 * (y - x + 1);
}
}
}
</pre>
</div>
...and it is trivial to modify this to draw filled circles (in four horizontal slices):
<div class="code">
<pre>
void fill_circle(int x0, int y0, int r, int c) {
int x = r;
int y = 0;
int radiusError = 1 - x;
while(x >= y)
{
// top
draw_line(-y + x0, -x + y0, y + x0, -x + y0, c);
// upper middle
draw_line(-x + x0, -y + y0, x + x0, -y + y0, c);
// lower middle
draw_line(-x + x0, y + y0, x + x0, y + y0, c);
// bottom
draw_line(-y + x0, x + y0, y + x0, x + y0, c);
y++;
if (radiusError < 0)
{
radiusError += 2 * y + 1;
} else {
x--;
radiusError+= 2 * (y - x + 1);
}
}
}
</pre>
</div>
</div>
<br />
<div style="text-align: justify;">
Now use these to draw something - a quick (admittedly pretty much mindless) example:
<div class="code">
<pre>
void draw() {
int x;
// some pixels
for (x = 0; x < vinfo.xres; x+=5) {
put_pixel(x, vinfo.yres / 2, WHITE);
}
// some lines (note the quite likely 'Moire pattern')
for (x = 0; x < vinfo.xres; x+=20) {
draw_line(0, 0, x, vinfo.yres, GREEN);
}
// some rectangles
draw_rect(vinfo.xres / 4, vinfo.yres / 2 + 10,
vinfo.xres / 4, vinfo.yres / 4, PURPLE);
draw_rect(vinfo.xres / 4 + 10, vinfo.yres / 2 + 20,
vinfo.xres / 4 - 20, vinfo.yres / 4 - 20, PURPLE);
fill_rect(vinfo.xres / 4 + 20, vinfo.yres / 2 + 30,
vinfo.xres / 4 - 40, vinfo.yres / 4 - 40, YELLOW);
// some circles
int d;
for(d = 10; d < vinfo.yres / 6; d+=10) {
draw_circle(3 * vinfo.xres / 4, vinfo.yres / 4, d, RED);
}
fill_circle(3 * vinfo.xres / 4, 3 * vinfo.yres / 4,
vinfo.yres / 6, ORANGE);
fill_circle(3 * vinfo.xres / 4, 3 * vinfo.yres / 4,
vinfo.yres / 8, RED);
}
</pre>
</div>
...might be a good idea to make sure we are in 8 bit mode for the color constants to work... Full code in <a href=https://github.com/rst-/raspberry-compote/blob/master/fb/fbtestXX.c>GitHub</a>.
</div>
<br />
<div style="text-align: justify;">
[Continued in next part <a href="http://raspberrycompote.blogspot.com/2014/04/low-level-graphics-on-raspberry-pi-text.html">Text</a>]
</div>
<br />Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-22541686660013449532014-04-03T12:07:00.002+01:002014-04-03T12:10:16.297+01:00Rant "javac: invalid target release: 1.6"<div style="text-align: justify;">
Argh, now I just cannot help myself not to blurt this out. One of the most frustrating small knacks I have come up against lately.
</div>
<br/>
<div style="text-align: justify;">
At work, I need to rebuild one customer specific <a href=http://en.wikipedia.org/wiki/Java_(programming_language)>Java</a> web application using JDK 1.6 to match the base product change to target 1.6.
</div>
<br/>
<div style="text-align: justify;">
So I login to the build machine, check out that there is JDK 1.6 installed, update the <a href=http://ant.apache.org/>Ant</a> <span class="codetoken">build.xml</span> with new JDK location + target and start the build...
<div class="output">
<pre>
...
compile:
[echo] ============================================================
[echo] Compiling source files
[javac] Compiling 12 source files to C:\projects\xxx\build\classes
[javac] javac: invalid target release: 1.6
[javac] Usage: javac <options> <source files>
[javac] where possible options include:
[javac] -g Generate all debugging info
...
</pre>
</div>
WHAT??!! I scratch my head and try editing all the related properties and build script files - trying out all combinations of parameters ...to no avail.
</div>
<br/>
<div style="text-align: justify;">
Ok... Google gives me a load of links to discussions like this one on <a href=http://stackoverflow.com/questions/4956209/problem-in-ant-build-invalid-target-release>stackoverflow</a>:
<div class="output">
<pre>
Q:
problem in ant build
...
ant source and target to 1.6 en variable path to jdk 1.6
A:
It might be useful for some to know that ant looks at the JAVA_HOME
variable when deciding which Java version to use
A:
Check the used Java-version with adding following line to your
target (at the beginning): ...
etc
</pre>
</div>
Well... In our ant script we tell the exact path to the javac executable, so it cannot be that - changing the <span class="codetoken">JAVA_HOME</span> obviously has no effect in this case either.
</div>
<br/>
<div style="text-align: justify;">
So to debug the issue I fire up a command prompt and try it manually:
<div class="output">
<pre>
C:\>%JAVA_HOME%\bin\javac -version
javac 1.6.0_21
javac: no source files
Usage: javac <options> <source files>
where possible options include:
...
C:\>%JAVA_HOME%\bin\javac -target 1.6
javac: invalid target release: 1.6
Usage: javac <options> <source files>
where possible options include:
...
</pre>
</div>
BOOM!! There it is - the same error message outside of Ant.
</div>
<br/>
<div style="text-align: justify;">
Hmm, now lets try on another JDK 1.6 update:
<div class="output">
<pre>
C:\>set JAVA_HOME=C:\Progra~1\Java\jdk1.6.0_45
C:\>%JAVA_HOME%\bin\javac -version
javac 1.6.0_45
C:\>%JAVA_HOME%\bin\javac -target 1.6
javac: no source files
Usage: javac <options> <source files>
use -help for a list of possible options
</pre>
</div>
...so there have been some broken JDK build(s) out there and the solution is to upgrade the JDK. Phew.
</div>
<br/>
<div style="text-align: justify;">
Luckily I get paid for this ;) ...and the Oracle JDK8 for Raspberry Pi (well, "Linux ARM v6/v7 Hard Float ABI") is still pretty awesome :D
</div>
<br/>
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-49255866500758409262014-03-22T16:05:00.003+00:002014-03-22T16:24:54.319+00:00Programming language (micro) benchmark<div style="text-align: justify;">
Out of curiosity, arising from a discussion on the Raspberry Pi forum, I did some micro benchmarking of <i>C</i>, <i>Java</i> and <i>Python</i> programming languages on Raspberry Pi. The application loops through numbers from 3 to 10000 and checks whether it is a <a href=http://en.wikipedia.org/wiki/Prime_number>prime number</a>. I tried my best to make the code as close the same in all three languages (even not using boolean types) and eliminate any interference like console output. Also I did repeat the tests multiple times; seeing only some milliseconds deviation between runs.
</div>
<br/>
<div style="text-align: justify;">
Python code:
<div class="code">
<pre>
result = 0
result |= 2
for i in range(3,10001):
prime = 1
for j in range(2, i):
k = i/j
l = k*j
if l == i:
prime = 0
if prime == 1:
result |= i
print result
</pre>
</div>
Saved as <span class="codetoken">prime2.py</span> and ran <a href=http://linux.die.net/man/1/time>timing</a> the execution:
<div class="output">
<pre>
$ time python prime2.py
16383
real 8m25.081s
user 8m7.960s
sys 0m1.230s
$ python --version
Python 2.7.3
</pre>
</div>
...yes, that is 8 and a half minutes.
</div>
<br/>
<div style="text-align: justify;">
C code (repeats the test function 10 times to match Java...):
<div class="code">
<pre>
#include <stdio.h>
int test() {
int result = 0;
result |= 2;
int i;
for (i=3;i<=10000;i++) {
int prime = 1;
int j;
for (j=2;j<i;j++) {
int k = i/j;
int l = k*j;
if (l==i) prime = 0;
}
if (prime) result |= i;
}
printf("%i\n", result);
}
int main() {
int i;
for (i = 0; i < 10; i++) {
test();
}
}
</pre>
</div>
Saved as <span class="codetoken">prime2.c</span>, compiled with <span class="codetoken">gcc -O2 -o prime2 prime2.c</span> (with typical optimisation level 2) and ran:
<div class="output">
<pre>
$ time ./prime2
16383
16383
16383
16383
16383
16383
16383
16383
16383
16383
real 0m35.957s
user 0m35.780s
sys 0m0.070s
$ gcc --version
gcc (Debian 4.6.3-14+rpi1) 4.6.3
</pre>
</div>
...which is 36 seconds for 10 rounds = less than 4 seconds for the same one round as in Python... (gcc (Debian 4.6.3-14+rpi1) 4.6.3)
</div>
<br/>
<div style="text-align: justify;">
Java code (repeats the test function 10 times to eliminate the effect of virtual machine start up time and possibly give the Hotspot compiler a chance to kick in):
<div class="code">
<pre>
public class Prime2 {
public static void main(String [] args) {
for (int i = 0; i < 10; i++) {
test();
}
}
public static void test() {
int result = 0;
result |= 2;
for (int i=3;i<=10000;i++) {
boolean prime = true;
for (int j=2;j<i;j++) {
int k = i/j;
int l = k*j;
if (l==i) prime = false;
}
if (prime) result |= i;
}
System.out.println(result);
}
}
</pre>
</div>
Saved as <span class="codetoken">Prime2.java</span>, compiled with <span class="codetoken">javac Prime2.java</span> and ran:
<div class="output">
<pre>
$ time java Prime2
16383
16383
16383
16383
16383
16383
16383
16383
16383
16383
real 0m33.490s
user 0m33.130s
sys 0m0.240s
$ java -version
java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b36e)
Java HotSpot(TM) Client VM (build 25.0-b04, mixed mode)
</pre>
</div>
...which is pretty impressive - even slightly faster than C - the Oracle guys have done a good job with optimising the Java platform for RPi.
</div>
<br/>
<div style="text-align: justify;">
Of course this is just a <i>micro</i> benchmark and one cannot draw too definite conclusions from the results. Also there are other aspects (accessibility, productivity, availability of domain specific libraries etc.) to consider when choosing a programming language.
</div>
<br/>Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-75127405026233227372014-03-21T15:55:00.002+00:002015-01-16T17:00:18.241+00:00Low-level Graphics on Raspberry Pi (part X+2)<div style="text-align: justify;">
In the previous <a href=http://raspberrycompote.blogspot.com/2014/03/low-level-graphics-on-raspberry-pi-part_16.html>part</a> we did some animation with page flipping ...requiring a bit ugly 'incantation' outside of the application code.
</div>
<br/>
<div style="text-align: justify;">
It is worth noting that not all animation or screen effects require page flipping (or v-syncing). There is no need for such for example if the change between 'frames' is small enough - like updating textual or numerical indicators - or the change is <a href=http://en.wikipedia.org/wiki/Stochastic>stochastic</a> enough - like for example the legendary (at least back in the day in early-mid 1990's) <a href=http://en.wikipedia.org/wiki/Demo_effect#Chunky-pixel_effects>fire effect</a>.
</div>
<br/>
<div style="text-align: justify;">
The fire effect might in fact work as a good example ...also admittedly I love it myself and cannot wait to show it off ;) I wrote my first version of the code for a <a href="http://en.wikipedia.org/wiki/Intel_80386#The_i386SX_variant">386sx</a> PC with a plain vanilla <a href="http://en.wikipedia.org/wiki/Video_Graphics_Array">VGA</a> card - tweaked into 320x240 pixels 256 color <a href=http://en.wikipedia.org/wiki/Mode_X>'Mode X'</a> somewhere around 1993 after seeing the effect on one university course mate's <a href="http://en.wikipedia.org/wiki/Amiga">Amiga</a>. Part of the <a href=http://en.wikipedia.org/wiki/Demoscene>demoscene</a> ethos and big part of the fun was of course to not copy somebody else's ready-made code but to figure out the idea your self. However I am now going to be a spoiler and reveal the code to this effect (well, there are versions already floating in the internet)...
</div>
<br/>
<div style="text-align: justify;">
First we have to come up with a nice fiery color palette - this should give us a nice one from golden yellow, to orange, to red, to fading the red to black:
<div class="code">
<pre>
// Create palette
unsigned short r[256]; // red
unsigned short g[256]; // green
unsigned short b[256]; // blue
int i;
for (i = 0; i < 256; i++) {
if (i < 32) {
r[i] = i * 7 << 8;
g[i] = b[i] = 0;
}
else if (i < 64) {
r[i] = 224 << 8;
g[i] = (i - 32) * 4 << 8;
b[i] = 0;
}
else if (i < 96) {
r[i] = 224 + (i - 64) << 8;
g[i] = 128 + (i - 64) * 3 << 8;
b[i] = 0;
}
else {
r[i] = g[i] = 255 << 8;
b[i] = 128 << 8;
}
}
struct fb_cmap palette;
palette.start = 0;
palette.len = 256;
palette.red = r;
palette.green = g;
palette.blue = b;
palette.transp = 0; // null == no transparency settings
// Set palette
if (ioctl(fbfd, FBIOPUTCMAP, &palette)) {
printf("Error setting palette.\n");
}
</pre>
</div>
...and remember to restore the palette at the end of the execution! Good exercise would be to work out other nice color transitions - something like gas fire like white-yellow-blue for example.
</div>
<br/>
<div style="text-align: justify;">
For plotting the pixels, the algorithm has three phases: <i>seed</i>, <i>smooth</i> and <i>convect</i>. In seed phase, we 'sow the seeds for the fire' by plotting semi-randomly bright yellow pixels along the bottom line of the screen. In smooth phase, we scan through all pixels on the screen and average them with the surrounding pixels to smooth out clear color edges. And in the convect phase, we make the flames to rise up the screen slowly cooling down and fading into the background. As it is evident in the code, it is good to play around with the values for seed colors, frequency of seed pixels, smoothing factors etc:
<div class="code">
<pre>
// Draw
int maxx = var_info.xres - 1;
int maxy = var_info.yres - 1;
int n = 0, r, c, x, y;
int c0, c1, c2;
while (n++ < 200) {
// seed
for (x = 1; x < maxx; x++) {
r = rand();
c = (r % 4 == 0) ? 192 : 32;
put_pixel(x, maxy, fbp, &var_info, c);
if ((r % 4 == 0)) { // && (r % 3 == 0)) {
c = 2 * c / 3;
put_pixel(x - 1, maxy, fbp, &var_info, c);
put_pixel(x + 1, maxy, fbp, &var_info, c);
}
}
// smooth
for (y = 1; y < maxy - 1; y++) {
for (x = 1; x < maxx; x++) {
c0 = get_pixel(x - 1, y, fbp, &var_info);
c1 = get_pixel(x, y + 1, fbp, &var_info);
c2 = get_pixel(x + 1, y, fbp, &var_info);
c = (c0 + c1 + c1 + c2) / 4;
put_pixel(x, y - 1, fbp, &var_info, c);
}
}
// convect
for (y = 0; y < maxy; y++) {
for (x = 1; x < maxx; x++) {
c = get_pixel(x, y + 1, fbp, &var_info);
if (c > 0) c--;
put_pixel(x, y, fbp, &var_info, c);
}
}
}
</pre>
</div>
It appears that for this we need an utility function for reading the current value from a pixel on the screen:
<div class="code">
<pre>
// utility function to get a pixel
char get_pixel(int x, int y, void *fbp, struct fb_var_screeninfo *vinfo) {
unsigned long offset = x + y * vinfo->xres;
return *((char*)(fbp + offset));
}
</pre>
</div>
And then there's the annoying blinking console cursor we need to hide...
<div class="code">
<pre>
#include <linux/kd.h>
...
// hide cursor
char *kbfds = "/dev/tty";
int kbfd = open(kbfds, O_WRONLY);
if (kbfd >= 0) {
ioctl(kbfd, KDSETMODE, KD_GRAPHICS);
}
else {
printf("Could not open %s.\n", kbfds);
}
</pre>
</div>
...and remember to restore at end!<br/>
<br/>
[Full source available in <a href="https://github.com/rst-/raspberry-compote/blob/master/fb/fbfire.c">GitHub</a>]
</div>
<br/>
<div style="text-align: justify;">
This should produce the awesome effect as seen in this screenshot (already sneak-peeked in <a href=http://raspberrycompote.blogspot.ie/2013/01/low-level-graphics-on-raspberry-pi-part.html>part 2</a>):
<div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/-epHyE2zstAc/UP0nqIlTpeI/AAAAAAAAAFA/_hQxBWEz8Zc/s1600/fbfire2.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-epHyE2zstAc/UP0nqIlTpeI/AAAAAAAAAFA/_hQxBWEz8Zc/s320/fbfire2.gif" /></a></div>
Starfield, shadebobs and plasma effects would not require page flipping / v-syncing and might be worth attempting... some more examples for inspiration or dwelling in the good oldskool days for example <a href=http://archive.assembly.org/1992>here</a> ;)
</div>
<br/>
<div style="text-align: justify;">
[Continued in next part <a href="http://raspberrycompote.blogspot.com/2014/04/low-level-graphics-on-raspberry-pi.html">Shapes</a>]
</div>
<br />Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-68203546446018178482014-03-16T15:37:00.001+00:002015-01-27T16:01:50.389+00:00Low-level Graphics on Raspberry Pi (part X+1)<div style="text-align: justify;">
NOTE 2015-01-27: On later Raspbian builds this approach may lead to a lock up! It is adviced to use the 'pure fb' approach - code available in this <a href="http://raspberrycompote.blogspot.com/2015/01/low-level-graphics-on-raspberry-pi-part_27.html">post</a>.
</div>
<br/>
<div style="text-align: justify;">
In previous <a href=http://raspberrycompote.blogspot.com/2014/03/low-level-graphics-on-raspberry-pi-part_14.html>part</a> we tried a simple animation - with not so perfect results...
</div>
<br/>
<div style="text-align: justify;">
Obviously with so many different avenues to tackle for the Raspberry Pi driver developers it is not possible for us users to get everything 'for free' and at instant. I sure wish I had the time and/or the drive to attempt extending the fb driver myself ...or maybe the legendary 'Somebody Else' could do it ;) As the thing is, it does not seem that big of a job: there is already support for the 'page flipping' using double size buffer and panning the display in the Raspberry Pi firmware <a href=https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface]>Mailbox interface</a>.
</div>
<br/>
<div style="text-align: justify;">
In the meantime, we could take a stab at trying this out. Raspberry Pi forum users hacking on the 'bare metal' (thanks guys) pointed me before to look at the <span class="codetoken">arch/arm/mach-bcm2708/include/mach/vcio.h</span> in the RPi firmware GitHub <a href=https://github.com/raspberrypi/linux/tree/rpi-3.10.y/arch/arm/mach-bcm2708/include/mach/vcio.h>sources</a> and to the way to talk to the mailbox:
<div class="code">
<pre>
...
#include "vcio.h"
...
int mboxfd = 0;
...
// helper function to talk to the mailbox interface
static int mbox_property(void *buf)
{
if (mboxfd < -1) return -1;
int ret_val = ioctl(mboxfd, IOCTL_MBOX_PROPERTY, buf);
if (ret_val < 0) {
printf("ioctl_set_msg failed:%d\n", ret_val);
}
return ret_val;
}
// helper function to set the framebuffer virtual offset == pan
static unsigned set_fb_voffs(unsigned *x, unsigned *y)
{
int i=0;
unsigned p[32];
p[i++] = 0; // size
p[i++] = 0x00000000; // process request
p[i++] = 0x00048009; // get physical (display) width/height
p[i++] = 0x00000008; // buffer size
p[i++] = 0x00000000; // request size
p[i++] = *x; // value buffer
p[i++] = *y; // value buffer 2
p[i++] = 0x00000000; // end tag
p[0] = i*sizeof *p; // actual size
mbox_property(p);
*x = p[5];
*y = p[6];
return p[1];
}
...
void draw() {
...
// switch page
/*
vinfo.yoffset = cur_page * vinfo.yres;
vinfo.activate = FB_ACTIVATE_VBL;
if (ioctl(fbfd, FBIOPAN_DISPLAY, &vinfo)) {
printf("Error panning display.\n");
}
*/
vx = 0;
vy = cur_page * vinfo.yres;
set_fb_voffs(&vx, &vy);
//usleep(1000000 / fps);
}
...
// main
// open a char device file used for communicating with kernel mbox driver
mboxfd = open(DEVICE_FILE_NAME, 0);
if (mboxfd < 0) {
printf("Can't open device file: %s\n", DEVICE_FILE_NAME);
printf("Try creating a device file with: mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM);
}
...
</pre>
</div>
From the <span class="codetoken">"vcio.h"</span> we are using the two defines: <span class="codetoken">DEVICE_FILE_NAME "char_dev"</span> and <span class="codetoken"MAJOR_NUM 100></span>. This <span class="codetoken">char_dev</span> is a special file for communicating with the mailbox. The file must be created using the command <span class="codetoken">mknod</span> (see <a href=http://linux.die.net/man/2/mknod>man</a>):
<div class="output">
<pre>
$ sudo mknod char_dev c 100 0
</pre>
</div>
<div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/-1PiG5-ct9QQ/UyWvaVYaXVI/AAAAAAAAAJE/WSwLv2sHXyA/s1600/mknod.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-1PiG5-ct9QQ/UyWvaVYaXVI/AAAAAAAAAJE/WSwLv2sHXyA/s320/mknod.png" /></a></div>
Save the code as say <span class="codetoken">fbtestXII.c</span> (full source in <a href=https://github.com/rst-/raspberry-compote/blob/master/fb/fbtestXII.c>GitHub</a>), download the vcio.h file to the same directory, build with:
<div class="output">
<pre>
gcc -lrt -o fbtestXII fbtestXII.c
</pre>
</div> (as the code uses the clock functions from librt) and run with <span class="codetoken">./fbtestXII</span>. This should display the same gliding and bouncing rectangle, but this time with no tearing and with minimal flicker.
</div>
<br/>
<div style="text-align: justify;">
The program outputs the timing info - the (most likely) 16 seconds (and some 700 ms) comes from the <span class="codetoken">fps = 100</span> and <span class="codetoken">secs = 10</span> ...it is quite obvious that since the screen refresh is now tied to the vertical sync, we 'only' get 60 fps and 100 * 10 = 1000 loops takes 1000 / 60 = 16.6 s.
</div>
<br/>
<div style="text-align: justify;">
Now if we change the code a bit:
<div class="code">
<pre>
...
#define NUM_ELEMS 200
int xs[NUM_ELEMS];
int ys[NUM_ELEMS];
int dxs[NUM_ELEMS];
int dys[NUM_ELEMS];
...
void draw() {
int i, x, y, w, h, dx, dy;
struct timespec pt;
struct timespec ct;
struct timespec df;
// rectangle dimensions
w = vinfo.yres / 10;
h = w;
// start position (upper left)
x = 0;
y = 0;
int n;
for (n = 0; n < NUM_ELEMS; n++) {
int ex = rand() % (vinfo.xres - w);
int ey = rand() % (vinfo.yres - h);
//printf("%d: %d,%d\n", n, ex, ey);
xs[n] = ex;
ys[n] = ey;
int edx = (rand() % 10) + 1;
int edy = (rand() % 10) + 1;
dxs[n] = edx;
dys[n] = edy;
}
// move step 'size'
dx = 1;
dy = 1;
int fps = 60;
int secs = 10;
int vx, vy;
clock_gettime(CLOCK_REALTIME, &pt);
// loop for a while
for (i = 0; i < (fps * secs); i++) {
// change page to draw to (between 0 and 1)
cur_page = (cur_page + 1) % 2;
// clear the previous image (= fill entire screen)
clear_screen(0);
for (n = 0; n < NUM_ELEMS; n++) {
x = xs[n];
y = ys[n];
dx = dxs[n];
dy = dys[n];
// draw the bouncing rectangle
fill_rect(x, y, w, h, (n % 15) + 1);
// move the rectangle
x = x + dx;
y = y + dy;
// check for display sides
if ((x < 0) || (x > (vinfo.xres - w))) {
dx = -dx; // reverse direction
x = x + 2 * dx; // counteract the move already done above
}
// same for vertical dir
if ((y < 0) || (y > (vinfo.yres - h))) {
dy = -dy;
y = y + 2 * dy;
}
xs[n] = x;
ys[n] = y;
dxs[n] = dx;
dys[n] = dy;
}
// switch page
vx = 0;
vy = cur_page * vinfo.yres;
set_fb_voffs(&vx, &vy);
}
clock_gettime(CLOCK_REALTIME, &ct);
df = timediff(pt, ct);
printf("done in %ld s %5ld ms\n", df.tv_sec, df.tv_nsec / 1000000);
}
...
</pre>
</div>
(full <a href=https://github.com/rst-/raspberry-compote/blob/master/fb/fbtestXIII.c>source</a>)...and build with (optimisation on):
<div class="output">
<pre>
gcc -O2 -lrt -o fbtestXIII fbtestXIII.c
</pre>
</div>
...we should get 200 colorful, bouncing 'sprites' going all over the screen:
<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/-L8cKg5RQFA0/UyW98v9WM4I/AAAAAAAAAJU/jKpQDU3X0pI/s1600/sprites.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-L8cKg5RQFA0/UyW98v9WM4I/AAAAAAAAAJU/jKpQDU3X0pI/s320/sprites.jpg" /></a></div>
Using the "char_dev" (especially as it has to be created as root) is not the most elegant way, but so far the only solution I know (if we want to stick to the fb) and at least for some uses this may be quite enough.
</div>
<br/>
<div style="text-align: justify;">
[Continued in <a href="http://raspberrycompote.blogspot.com/2014/03/low-level-graphics-on-raspberry-pi-part_21.html">part X+2</a>>
</div>
<br/>
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-25041101061765317602014-03-14T12:19:00.000+00:002014-09-10T13:54:12.764+01:00Low-level Graphics on Raspberry Pi (part X)<div style="text-align: justify;">
Now that we have been <a href="http://raspberrycompote.blogspot.com/2013/04/low-level-graphics-on-raspberry-pi-part_3.html">gradually building</a> the example program to allow us to do something interesting - how about trying a bit of animation?
<div class="code">
<pre>
...
// helper function to draw a rectangle in given color
void fill_rect(int x, int y, int w, int h, int c) {
int cx, cy;
for (cy = 0; cy < h; cy++) {
for (cx = 0; cx < w; cx++) {
put_pixel(x + cx, y + cy, c);
}
}
}
// helper function to clear the screen - fill whole
// screen with given color
void clear_screen(int c) {
memset(fbp, c, vinfo.xres * vinfo.yres);
}
void draw() {
int i, x, y, w, h, dx, dy;
// start position (upper left)
x = 0;
y = 0;
// rectangle dimensions
w = vinfo.yres / 10;
h = w;
// move step 'size'
dx = 1;
dy = 1;
int fps = 100;
int secs = 10;
// loop for a while
for (i = 0; i < (fps * secs); i++) {
// clear the previous image (= fill entire screen)
clear_screen(8);
// draw the bouncing rectangle
fill_rect(x, y, w, h, 15);
// move the rectangle
x = x + dx;
y = y + dy;
// check for display sides
if ((x < 0) || (x > (vinfo.xres - w))) {
dx = -dx; // reverse direction
x = x + 2 * dx; // counteract the move already done above
}
// same for vertical dir
if ((y < 0) || (y > (vinfo.yres - h))) {
dy = -dy;
y = y + 2 * dy;
}
usleep(1000000 / fps);
// to be exact, would need to time the above and subtract...
}
}
...
</pre>
</div>
Save as <span class="codetoken">fbtestX.c</span> (complete code in <a href=https://github.com/rst-/raspberry-compote/blob/master/fb/fbtestX.c>GitHub</a>) - build with <span class="codetoken">make fbtestX</span>. This should give us a moving white rectangle that bounces off the screen sides... Unfortunately the updates are not smooth (at least on most displays) - there is a quite prominent <a href="http://en.wikipedia.org/wiki/Screen_tearing">tearing effect</a>.
</div>
<br/>
<div style="text-align: justify;">
Linux framebuffer <a href="http://lxr.free-electrons.com/source/include/linux/fb.h?v=3.6;a=arm">interface</a> does define some methods to overcome this - we could make the framebuffer virtual size double the height of the (smaller) physical one using the <span class="codetoken">FBIOPUT_VSCREENINFO</span> call:
<div class="code">
<pre>
// Set variable info
vinfo.xres = 640; // try a smaller resolution
vinfo.yres = 480;
vinfo.xres_virtual = 640;
vinfo.yres_virtual = 960; // double the physical
vinfo.bits_per_pixel = 8;
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo)) {
printf("Error setting variable information.\n");
}
//long int screensize = vinfo.xres * vinfo.yres;
// have to use the virtual size for the mmap...
long int screensize = vinfo.xres_virtual * vinfo.yres_virtual;
</pre>
</div>
And change our drawing loop to use the two halves of the virtual buffer using a call to <span class="codetoken">FBIOPAN_DISPLAY</span> for <a href="http://en.wikipedia.org/wiki/Flip-screen">page-flipping</a> tied to a <a href=http://en.wikipedia.org/wiki/Vertical_synchronization#Vertical_synchronization>vertical sync</a> using <span class="codetoken">FB_ACTIVATE_VBL</span>:
<div class="code">
<pre>
int vs = 0;
// initially show upper half (0) - draw to lower half (1)
int cur_half = 1;
for (i = 0; i < 1000; i++) {
fill_rect(x, y, 40, 40, 4);
x = x + dx;
y = y + dy;
if ((x < 0) || (x > (vinfo.xres - 40)) {
dx = -dx;
x = x + 2 * dx;
}
if ((y < 0) || (y > (vinfo.yres - 40)) {
dy = -dy;
y = y + 2 * dy;
}
// switch page
vinfo.yoffset = cur_page * vinfo.yres;
vinfo.activate = FB_ACTIVATE_VBL;
if (ioctl(fbfd, FBIOPAN_DISPLAY, &vinfo)) {
printf("Error panning display.\n");
}
}
</pre>
</div>
Unfortunately these calls have not been implemented in the <a href="https://github.com/raspberrypi/linux/blob/rpi-3.6.y/drivers/video/bcm2708_fb.c">RPi framebuffer driver</a> (does not seem to be in later versions either yet, see also <a href="http://www.raspberrypi.org/phpBB3/viewtopic.php?f=67&t=19073">http://www.raspberrypi.org/phpBB3/viewtopic.php?f=67&t=19073</a>). So running the above code (<a href=https://github.com/rst-/raspberry-compote/blob/master/fb/fbtestXI.c>full code</a>) results in repeated output of <span class="output">Error panning display.</span> and the rectangle flashing even worse (as we miss every second screen update by drawing outside of the visible area).
</div>
<br/>
<div style="text-align: justify;">
[Continued in <a href=http://raspberrycompote.blogspot.com/2014/03/low-level-graphics-on-raspberry-pi-part_16.html>next part</a>]
</div>
<br/>
<div style="text-align: justify;">
[UPDATE on changes in the fb driver <a href="http://raspberrycompote.blogspot.com/2014/09/low-level-graphics-on-raspberry-pi-part.html">here</a>]
</div>
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com1tag:blogger.com,1999:blog-5047934568841336576.post-22413149644682822272014-03-14T12:09:00.002+00:002014-03-14T12:20:48.897+00:00Restart<div style="text-align: justify;">
Well, nearly a full year in hibernation. Life happens: family, day job, second job, other hobbies... and by the last <a href=http://raspberrycompote.blogspot.ie/2013/04/low-level-graphics-on-raspberry-pi-part_3.html>post</a> the tutorial series looked sort of 'good enough' which caused a kind of a writer's block.
</div>
<br/>
<div style="text-align: justify;">
Apologies if someone was feeling left hanging - also apologies for not answering many comments posted. I have now disabled comments as I cannot commit to answering - also I might not be a guru enough for many of them ;) I have added a link on the right panel to the <a href=http://www.raspberrypi.org/forum/viewtopic.php?f=67&t=30720>discussion</a> on the <a href=http://www.raspberrypi.org/forum/>Raspberry Pi forum</a> - where I will pop in from time to time, but more importantly there should be other like-minded, helpful people too on the board.
</div>
<br/>
<div style="text-align: justify;">
Ok, enough of that - let's take a look at some graphics coding in the next part of <a href=http://raspberrycompote.blogspot.ie/2014/03/low-level-graphics-on-raspberry-pi-part_14.html>'Low-level Graphics on Raspberry Pi'</a>.
</div>
<br/>
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-9222896105217863592013-04-03T11:26:00.000+01:002014-04-18T18:41:23.498+01:00Low-level Graphics on Raspberry Pi (part eight)<div style="text-align: justify;">
Last <a href="http://raspberrycompote.blogspot.com/2013/04/low-level-graphics-on-raspberry-pi-part.html">time</a>, we looked at the differences between display modes regarding color depths. Another attribute of a display mode is the resolution - by default, RPi uses the full HD resolution 1920x1080 as we saw in the <a href="http://raspberrycompote.blogspot.ie/2012/12/low-level-graphics-on-raspberry-pi-part_9509.html">first part</a> (of course depending on the actual display attached).
</div>
<br/>
<div style="text-align: justify;">
Basically this can be changed to (almost) anything if needed/wanted - one obvious reason would be to limit the number of pixels RPi has to handle. You might have noticed that the color gradients in the previous example appear on the screen somewhat slowly (especially if using the full HD resolution)?
</div>
<br/>
<div style="text-align: justify;">
Let's experiment a bit... As briefly mentioned before, there is an utility for changing the frame buffer parameters called <span class="codetoken">fbset</span> (see <a href="http://linux.die.net/man/8/fbset">man fbset</a>). Now if we assume the original resolution is the full HD, running <span class="codetoken">fbtest7</span> would look like:
<div class="output">
<pre>
$ ./fbtest7
The framebuffer device was opened successfully.
Original 1920x1080, 16bpp
$
</pre>
</div>
...and the image appears like a roller blind drawn down. Now try the following sequence of commands (presented with output, so type only the text on lines starting with $ sign, not including the sign):
<div class="output">
<pre>
$ fbset -g 960 540 960 540 16
$ ./fbtest7
The framebuffer device was opened successfully.
Original 960x540, 16bpp
$ fbset -g 640 360 640 360 16
$ ./fbtest7
The framebuffer device was opened successfully.
Original 640x360, 16bpp
$ fbset -g 448 256 448 256 16
$ ./fbtest7
The framebuffer device was opened successfully.
Original 448x256, 16bpp
$
</pre>
</div>
...with about the same image appearing faster and faster. Also note that even though we change the resolution to smaller and smaller, the RPI VideoCore GPU scales the image up to fill the entire display - hardware accelerated up-scaling for free ;)
</div>
<br/>
<div style="text-align: justify;">
The effect on the image quality may not be that apparent with the color gradient example, so let's try something possibly a bit more descriptive:
<div class="code">
<pre>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
// 'global' variables to store screen info
char *fbp = 0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
// helper function to 'plot' a pixel in given color
void put_pixel(int x, int y, int c)
{
// calculate the pixel's byte offset inside the buffer
unsigned int pix_offset = x + y * finfo.line_length;
// now this is about the same as 'fbp[pix_offset] = value'
*((char*)(fbp + pix_offset)) = c;
}
// helper function for drawing - no more need to go mess with
// the main function when just want to change what to draw...
void draw() {
int x, y;
// fill the screen with blue
memset(fbp, 1, vinfo.xres * vinfo.yres);
// white horizontal lines every 10 pixel rows
for (y = 0; y < (vinfo.yres); y+=10) {
for (x = 0; x < vinfo.xres; x++) {
put_pixel(x, y, 15);
}
}
// white vertical lines every 10 pixel columns
for (x = 0; x < vinfo.xres; x+=10) {
for (y = 0; y < (vinfo.yres); y++) {
put_pixel(x, y, 15);
}
}
int n;
// select smaller extent
// (just in case of a portrait mode display)
n = (vinfo.xres < vinfo.yres) ? vinfo.xres : vinfo.yres;
// red diagonal line from top left
for (x = 0; x < n; x++) {
put_pixel(x, x, 4);
}
}
// application entry point
int main(int argc, char* argv[])
{
int fbfd = 0;
struct fb_var_screeninfo orig_vinfo;
long int screensize = 0;
// Open the file for reading and writing
fbfd = open("/dev/fb0", O_RDWR);
if (!fbfd) {
printf("Error: cannot open framebuffer device.\n");
return(1);
}
printf("The framebuffer device was opened successfully.\n");
// Get variable screen information
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
printf("Error reading variable information.\n");
}
printf("Original %dx%d, %dbpp\n", vinfo.xres, vinfo.yres,
vinfo.bits_per_pixel );
// Store for reset (copy vinfo to vinfo_orig)
memcpy(&orig_vinfo, &vinfo, sizeof(struct fb_var_screeninfo));
// Change variable info - force 8 bit
vinfo.bits_per_pixel = 8;
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo)) {
printf("Error setting variable information.\n");
}
// Get fixed screen information
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
printf("Error reading fixed information.\n");
}
// map fb to user mem
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
fbp = (char*)mmap(0,
screensize,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fbfd,
0);
if ((int)fbp == -1) {
printf("Failed to mmap.\n");
}
else {
// draw...
draw();
sleep(5);
}
// cleanup
munmap(fbp, screensize);
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo)) {
printf("Error re-setting variable information.\n");
}
close(fbfd);
return 0;
}
</pre>
</div>
Save that code as <span class="codetoken">fbtest8.c</span>, compile with <span class="codetoken">make fbtest8</span> and execute the following command sequence:
<div class="output">
<pre>
$ fbset -g 1920 1080 1920 1080 16
$ ./fbtest8
The framebuffer device was opened successfully.
Original 1920x1080, 16bpp
$ fbset -g 960 540 960 540 16
$ ./fbtest8
The framebuffer device was opened successfully.
Original 960x540, 16bpp
$ fbset -g 640 360 640 360 16
$ ./fbtest8
The framebuffer device was opened successfully.
Original 640x360, 16bpp
$ fbset -g 448 256 448 256 16
$ ./fbtest8
The framebuffer device was opened successfully.
Original 448x256, 16bpp
$
</pre>
</div>
...which should produce images like the ones here (the first one at 1920x1080 and the second at 448x256):
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-cx5uwM8R7Ec/UVv2uimPH9I/AAAAAAAAAEg/OPCPqzfI84k/s1600/fbtest8a.png" imageanchor="1" ><img border="0" src="http://4.bp.blogspot.com/-cx5uwM8R7Ec/UVv2uimPH9I/AAAAAAAAAEg/OPCPqzfI84k/s320/fbtest8a.png" /></a>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-3oHPlE-CME8/UVv2zAmAOmI/AAAAAAAAAEo/t4vBsZXUCmE/s1600/fbtest8b.png" imageanchor="1" ><img border="0" src="http://2.bp.blogspot.com/-3oHPlE-CME8/UVv2zAmAOmI/AAAAAAAAAEo/t4vBsZXUCmE/s320/fbtest8b.png" /></a>
</div>
</div>
<br/>
<div style="text-align: justify;">
Of course the resolution can be changed programmatically too (no need to leave it to the end-user) - change the variable info setting lines in the <span class="codetoken">main</span> to:
<div class="code">
<pre>
// Change variable info - force 8 bit and resolution
vinfo.bits_per_pixel = 8;
vinfo.xres = 320;
vinfo.yres = 240;
vinfo.xres_virtual = vinfo.xres;
vinfo.yres_virtual = vinfo.yres;
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo)) {
printf("Error setting variable information.\n");
}
</pre>
</div>
Save as <span class="codetoken">fbtest8b.c</span>, compile with <span class="codetoken">make fbtest8b</span> and execute with <span class="codetoken">./fbtest8b</span> ...and you should get the same image with even bigger pixels ...centered horizontally at the middle of the display with black borders at sides (if you have the typical widescreen display in landscape mode).
</div>
<br/>
<div style="text-align: justify;">
So it seems that VC GPU scales to 'best fit' keeping pixels square - if the specified resolution conforms to the display aspect ratio, the image will fill the entire display - if it does not, there will be black borders at either left&right or top&bottom. You might want to experiment with different <span class="codetoken">xres</span> and <span class="codetoken">yres</span> values (for example 512x256, more ideas maybe <a href="http://en.wikipedia.org/wiki/Display_resolution">here</a>) to find a suitable resolution for your use-case - bearing in mind that the GPU seems (based on the hello_pi examples and experimenting) to expect the xres to be a multiple of 32 and yres of 16 - if not, there may be some side effects... For example, for the 'fire effect' in the screenshot in <a href="http://raspberrycompote.blogspot.ie/2013/01/low-level-graphics-on-raspberry-pi-part.html">part two</a>, I had to go as low as 320x240 to get a bearable frame-rate.
</div>
<br/>
<div style="text-align: justify;">
Code available also in <a href="https://github.com/rst-/raspberry-compote/tree/master/fb">GitHub</a>
</div>
<br/>
<div style="text-align: justify;">
[Continued in <a href=http://raspberrycompote.blogspot.com/2014/03/low-level-graphics-on-raspberry-pi-part_14.html>part X</a>]
</div>
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-30223228282857061212013-04-02T11:03:00.002+01:002015-01-27T15:43:24.291+00:00Low-level Graphics on Raspberry Pi (part seven)<div style="text-align: justify;">
In the previous <a href="http://raspberrycompote.blogspot.com/2013/03/low-level-graphics-on-raspberry-pi-part_8.html">example</a>, we produced the same image in different display modes (color depths). Let's see if we can find some difference between the modes.
</div>
<br/>
<div style="text-align: justify;">
This example draws three color gradient circles partly overlapping:
<div class="code">
<pre>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
// 'global' variables to store screen info
char *fbp = 0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
void put_pixel_RGB24(int x, int y, int r, int g, int b)
{
// calculate the pixel's byte offset inside the buffer
// note: x * 3 as every pixel is 3 consecutive bytes
unsigned int pix_offset = x * 3 + y * finfo.line_length;
// now this is about the same as 'fbp[pix_offset] = value'
*((char*)(fbp + pix_offset)) = b;
*((char*)(fbp + pix_offset + 1)) = g;
*((char*)(fbp + pix_offset + 2)) = r;
}
void put_pixel_RGB565(int x, int y, int r, int g, int b)
{
// calculate the pixel's byte offset inside the buffer
// note: x * 2 as every pixel is 2 consecutive bytes
unsigned int pix_offset = x * 2 + y * finfo.line_length;
// now this is about the same as 'fbp[pix_offset] = value'
// but a bit more complicated for RGB565
//unsigned short c = ((r / 8) << 11) + ((g / 4) << 5) + (b / 8);
unsigned short c = ((r / 8) * 2048) + ((g / 4) * 32) + (b / 8);
// write 'two bytes at once'
*((unsigned short*)(fbp + pix_offset)) = c;
}
// helper function for drawing - no more need to go mess with
// the main function when just want to change what to draw...
void draw() {
int x, y;
int r, g, b;
int dr;
int cr = vinfo.yres / 3;
int cg = vinfo.yres / 3 + vinfo.yres / 4;
int cb = vinfo.yres / 3 + vinfo.yres / 4 + vinfo.yres / 4;
for (y = 0; y < (vinfo.yres); y++) {
for (x = 0; x < vinfo.xres; x++) {
dr = (int)sqrt((cr - x)*(cr - x)+(cr - y)*(cr - y));
r = 255 - 256 * dr / cr;
r = (r >= 0) ? r : 0;
dr = (int)sqrt((cg - x)*(cg - x)+(cr - y)*(cr - y));
g = 255 - 256 * dr / cr;
g = (g >= 0) ? g : 0;
dr = (int)sqrt((cb - x)*(cb - x)+(cr - y)*(cr - y));
b = 255 - 256 * dr / cr;
b = (b >= 0) ? b : 0;
if (vinfo.bits_per_pixel == 16) {
put_pixel_RGB565(x, y, r, g, b);
}
else {
put_pixel_RGB24(x, y, r, g, b);
}
}
}
}
// application entry point
int main(int argc, char* argv[])
{
int fbfd = 0;
struct fb_var_screeninfo orig_vinfo;
long int screensize = 0;
// Open the file for reading and writing
fbfd = open("/dev/fb0", O_RDWR);
if (!fbfd) {
printf("Error: cannot open framebuffer device.\n");
return(1);
}
printf("The framebuffer device was opened successfully.\n");
// Get variable screen information
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
printf("Error reading variable information.\n");
}
printf("Original %dx%d, %dbpp\n", vinfo.xres, vinfo.yres,
vinfo.bits_per_pixel );
// Store for reset (copy vinfo to vinfo_orig)
memcpy(&orig_vinfo, &vinfo, sizeof(struct fb_var_screeninfo));
// Get fixed screen information
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
printf("Error reading fixed information.\n");
}
// map fb to user mem
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
fbp = (char*)mmap(0,
screensize,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fbfd,
0);
if ((int)fbp == -1) {
printf("Failed to mmap.\n");
}
else {
// draw...
draw();
sleep(5);
}
// cleanup
munmap(fbp, screensize);
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo)) {
printf("Error re-setting variable information.\n");
}
close(fbfd);
return 0;
}
</pre>
</div>
Save the new code (available also on <a href="https://github.com/rst-/raspberry-compote/tree/master/fb">GitHub</a>) to fbtest7.c and compile using this command (as we now use the <span class="codetoken">sqrt()</span> function the math library, we need to tell the linker this with the '-lm' directive):
<div class="output">
gcc -o fbtest7 -lm fbtest7.c
</div>
And then execute the following sequence:
<div class="output">
<pre>
fbset -depth 16
./fbtest7
fbset -depth 24
./fbtest7
</pre>
</div>
...note how in the 16 bit mode there are noticeable bands in the color gradients - less so in the 24 bit mode. Note that the above code does not work in the 8 bit mode - it could be modified to produce similar enough image by setting the palette values suitably.
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-EHKmStK5Uy4/UVqrgxYM9vI/AAAAAAAAAEQ/9Df4ibyxQ0Y/s1600/cblobs16.png" imageanchor="1" ><img border="0" src="http://3.bp.blogspot.com/-EHKmStK5Uy4/UVqrgxYM9vI/AAAAAAAAAEQ/9Df4ibyxQ0Y/s320/cblobs16.png" /></a>
</div>
</div>
<br/>
<div style="text-align: justify;">
[Continued in <a href="http://raspberrycompote.blogspot.com/2013/04/low-level-graphics-on-raspberry-pi-part_3.html">part eight</a>]
</div>
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-56849282758182065582013-03-08T12:57:00.001+00:002014-04-18T18:40:57.476+01:00Low-level Graphics on Raspberry Pi (part six)<div style="text-align: justify;">
In the previous <a href="http://raspberrycompote.blogspot.com/2013/03/low-level-graphics-on-raspberry-pi-part_7.html">posts</a> we have been plotting pixels using a 8 bit, 256 color, palette display mode. In this mode, every byte of the framebuffer (mmap'ed) memory block present one byte and the value of the byte is an index to the palette (see <a href="http://raspberrycompote.blogspot.ie/2013/01/low-level-graphics-on-raspberry-pi-part_22.html">part three</a>). So to get the color bars in the previous examples, we have plotted values of <span class"codetoken">0</span> (zero) to the first bar (black), values of <span class"codetoken">1</span> (one) to the second bar (blue) and so on... This picture illustrates the idea - each cell presents one pixel (some columns skipped for compacting), showing both the byte value and the resulting color:
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-Ph7Zn3egGTo/UTi2cRJP61I/AAAAAAAAAC0/QS-86wAaiA4/s1600/8bit_image_pixels.png" imageanchor="1" ><img border="0" src="http://3.bp.blogspot.com/-Ph7Zn3egGTo/UTi2cRJP61I/AAAAAAAAAC0/QS-86wAaiA4/s320/8bit_image_pixels.png" /></a>
</div>
Here is the pixel plotting function used:
<div class="code">
<pre>
void put_pixel(int x, int y, int c)
{
// calculate the pixel's byte offset inside the buffer
unsigned int pix_offset = x + y * finfo.line_length;
// now this is about the same as 'fbp[pix_offset] = value'
*((char*)(fbp + pix_offset)) = c;
}
</pre>
</div>
So we are storing one byte (that '<span class="codetoken">char *</span>' there) ...obviously we could (/should) have defined the color parameter <span class="codetoken">c</span> as a <span class="codetoken">char</span> too, but... (the above code takes the lowest byte of the four byte integer variable, so works as is).
</div>
<br/>
<div style="text-align: justify;">
Well, how about other display modes? We have noticed already (<a href="http://raspberrycompote.blogspot.ie/2012/12/low-level-graphics-on-raspberry-pi-part_9509.html">part one</a>) that the default mode on RPi is 16 bit and quite often one comes across mentions of 24 bit and 32 bit modes. I suppose the easiest of these to begin with would be the 24 bit mode: 3 bytes per pixel - one byte per each RGB (red, green, blue) value. The RGB values are very similar to the values in the palette for the 8 bit mode. To illustrate this, in the following image we have the two leftmost pixels of the two first color bars - the first pixel occupies three first bytes of the memory buffer. For the black pixels all three byte values are zeroes - for the blue pixels the 'R' and 'G' bytes are zero and 'B' byte is 255 (= full blue):
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-lwBYWMzc5I4/UTi-IF1JzHI/AAAAAAAAADU/Im1mRcW0TNo/s1600/24bit_image_pixels.png" imageanchor="1" ><img border="0" src="http://1.bp.blogspot.com/-lwBYWMzc5I4/UTi-IF1JzHI/AAAAAAAAADU/Im1mRcW0TNo/s320/24bit_image_pixels.png" /></a>
</div>
This could be implemented as the following pixel plotting code:
<div class="code">
<pre>
void put_pixel_RGB24(int x, int y, int r, int g, int b)
{
// calculate the pixel's byte offset inside the buffer
// note: x * 3 as every pixel is 3 consecutive bytes
unsigned int pix_offset = x * 3 + y * finfo.line_length;
// now this is about the same as 'fbp[pix_offset] = value'
*((char*)(fbp + pix_offset)) = r;
*((char*)(fbp + pix_offset + 1)) = g;
*((char*)(fbp + pix_offset + 2)) = b;
}
</pre>
</div>
</div>
<br/>
<div style="text-align: justify;">
The RPi default 16 bit RGB565 is slightly more complex - there are 2 bytes per pixel and the color components are encoded so that 5 first bits are for the red, 6 middle bits for green and 5 last bits for blue:
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-6rHVBMav0cw/UTjII2cTchI/AAAAAAAAAEA/7z7EpMoy58w/s1600/16bit_word_bits.png" imageanchor="1" ><img border="0" src="http://4.bp.blogspot.com/-6rHVBMav0cw/UTjII2cTchI/AAAAAAAAAEA/7z7EpMoy58w/s320/16bit_word_bits.png" /></a>
</div>
In the format similar to the above ones, the memory buffer would look something like this:
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-YREXz0DOgpE/UTjDclw9vYI/AAAAAAAAADk/dK0pNmQpkIU/s1600/16bit_image_pixels.png" imageanchor="1" ><img border="0" src="http://1.bp.blogspot.com/-YREXz0DOgpE/UTjDclw9vYI/AAAAAAAAADk/dK0pNmQpkIU/s320/16bit_image_pixels.png" /></a>
</div>
...the blue value <span class="codetoken">31</span> comes from the fact that there are <span class="codetoken">5</span> bits for blue and the binary value of <span class="codetoken">0b11111</span> is <span class="codetoken">31</span> in decimal. Full red would be <span class="codetoken">0b1111100000000000</span> (63488) so the bytes for full red would be <span class="codetoken">248</span> and <span class="codetoken">0</span> - full green would be <span class="codetoken">0b0000011111100000</span> (2016) so the bytes <span class="codetoken">7</span> and <span class="codetoken">224</span>.
</div>
<br/>
<div style="text-align: justify;">
The RGB565 pixe plotting function would be something along this:
<div class="code">
<pre>
void put_pixel_RGB565(int x, int y, int r, int g, int b)
{
// calculate the pixel's byte offset inside the buffer
// note: x * 2 as every pixel is 2 consecutive bytes
unsigned int pix_offset = x * 2 + y * finfo.line_length;
// now this is about the same as 'fbp[pix_offset] = value'
// but a bit more complicated for RGB565
unsigned short c = ((r / 8) << 11) + ((g / 4) << 5) + (b / 8);
// or: c = ((r / 8) * 2048) + ((g / 4) * 32) + (b / 8);
// write 'two bytes at once'
*((unsigned short*)(fbp + pix_offset)) = c;
}
</pre>
</div>
The red value has 5 bits, so can be in the range 0-31, therefore divide the original 0-255 value by 8. It is stored in the first 5 bits, so multiply by 2048 or shift 11 bits left. The green has 6 bits, so can be in the range 0-63, divide by 4, and multiply by 32 or shift 5 bits left. Finally the blue has 5 bits and is stored at the last bits, so no need to move.
</div>
<br/>
<div style="text-align: justify;">
The 32 bit mode is usually so called ARGB - where there are 4 bytes per pixel, A standing for 'alpha' = transparency and the rest just like in the RGB24. Modifying the <span class="codetoken">put_pixel_RGB24()</span> to <span class="codetoken">put_pixel_ARGB32()</span> should be trivial.
</div>
<br/>
<div style="text-align: justify;">
Note that there are several other display (and especially image and video) modes as well, but the ones covered here are the most standard ones for Linux framebuffers.
</div>
<br/>
<div style="text-align: justify;">
To test the above pixel plotting functions, we could try the following (continuing from the code in part five):
<div class="code">
<pre>
void draw() {
int x, y;
for (y = 0; y < (vinfo.yres / 2); y++) {
for (x = 0; x < vinfo.xres; x++) {
// color based on the 16th of the screen width
int c = 16 * x / vinfo.xres;
if (vinfo.bits_per_pixel == 8) {
put_pixel(x, y, c);
}
else if (vinfo.bits_per_pixel == 16) {
put_pixel_RGB565(x, y, def_r[c], def_g[c], def_b[c]);
}
else if (vinfo.bits_per_pixel == 24) {
put_pixel_RGB24(x, y, def_r[c], def_g[c], def_b[c]);
}
}
}
}
...
// in main()
// comment out setting the bit depth
// Change variable info
/* use: 'fbset -depth x' to test different bpps
vinfo.bits_per_pixel = 8;
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo)) {
printf("Error setting variable information.\n");
}
*/
// also can comment out setting the palette...
// change the calculation of required memory
// map fb to user mem
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
...
</pre>
</div>
Save the new code to <span class="codetoken">fbtest6.c</span>, compile and then execute the following sequence:
<div class="output">
<pre>
fbset -depth 8
./fbtest6
fbset -depth 24
./fbtest6
fbset -depth 16
./fbtest6
</pre>
</div>
...this should yield three times the exact same color bars. Full source code available in <a href="https://github.com/rst-/raspberry-compote/tree/master/fb">github</a>.
</div>
<br/>
<div style="text-align: justify;">
[Continued in <a href="http://raspberrycompote.blogspot.com/2013/04/low-level-graphics-on-raspberry-pi-part.html">part seven</a>]
</div>
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-43871836495237023512013-03-07T15:08:00.002+00:002014-04-18T18:40:41.166+01:00Low-level Graphics on Raspberry Pi (part five) <div style="text-align: justify;">
So far we have used some fixed palette values for the colors (see <a href="http://raspberrycompote.blogspot.com/2013/03/low-level-graphics-on-raspberry-pi-part.html">part four</a>) - namely 0-15 to draw the 16 bars. These happen to be the default Linux framebuffer colors (slight variations between distributions to be expected). Since we are using palette indexes, we don't really know what are the actual colors output. The Linux framebuffer <a href="http://lxr.free-electrons.com/source/include/linux/fb.h?v=3.6;a=arm">interface</a> provides a function <span class="codetoken">FBIOGETCMAP</span> to read the color palette:
<div class="code">
<pre>
// Get palette information
unsigned short r[256];
unsigned short g[256];
unsigned short b[256];
unsigned short a[256];
memset(r, 0, 256 * sizeof(unsigned short));
memset(g, 0, 256 * sizeof(unsigned short));
memset(b, 0, 256 * sizeof(unsigned short));
memset(a, 0, 256 * sizeof(unsigned short));
struct fb_cmap pal;
pal.start = 0;
pal.len = 0;
pal.red = r;
pal.green = g;
pal.blue = b;
pal.transp = a;
if (ioctl(fbfd, FBIOGETCMAP, &pal)) {
printf("Error reading palette.\n");
}
</pre>
</div>
...would give us the red, green and blue components of the colors in the palette. So most likely <span class="codetoken">r[0]=0, g[0]=0, b[0]=0</span> for the color index 0 i.e. black (#000000 in HTML) - <span class="codetoken">r[1]=0, g[1]=0, b[1]=255</span> for color index 1 i.e. blue (#0000FF). Colors from index 16 onwards are most likely all black.
</div>
<br/>
<div style="text-align: justify;">
Unfortunately reading this information is not supported by the RPi framebuffer driver ...this surely is not how I wanted these posts to be Raspberry Pi specific :(
</div>
<br/>
<div style="text-align: justify;">
After a bit of trial and error (and 'stealing' the initial values from another Linux system using the above code), I managed to get pretty close to the RPi default colors. In this example we initialise some hard-coded values (note that I use the possibly more familiar range 0-255, matching many systems like the HTML color scheme) for the colors (the enum is not used here but might prove handy later on - think of <span class="codetoken">put_pixel(x, y, RED)</span>), set them to the system palette starting at index 16 (i.e. just after the default colors) and then draw the familiar color bars at the top half of the screen - and bars with same colors but using different palette indexes at the lower half for comparison:
<div class="code">
<pre>
...
// after includes
// default framebuffer palette
typedef enum {
BLACK = 0, /* 0, 0, 0 */
BLUE = 1, /* 0, 0, 172 */
GREEN = 2, /* 0, 172, 0 */
CYAN = 3, /* 0, 172, 172 */
RED = 4, /* 172, 0, 0 */
PURPLE = 5, /* 172, 0, 172 */
ORANGE = 6, /* 172, 84, 0 */
LTGREY = 7, /* 172, 172, 172 */
GREY = 8, /* 84, 84, 84 */
LIGHT_BLUE = 9, /* 84, 84, 255 */
LIGHT_GREEN = 10, /* 84, 255, 84 */
LIGHT_CYAN = 11, /* 84, 255, 255 */
LIGHT_RED = 12, /* 255, 84, 84 */
LIGHT_PURPLE = 13, /* 255, 84, 255 */
YELLOW = 14, /* 255, 255, 84 */
WHITE = 15 /* 255, 255, 255 */
} COLOR_INDEX_T;
static unsigned short def_r[] =
{ 0, 0, 0, 0, 172, 172, 172, 172,
84, 84, 84, 84, 255, 255, 255, 255};
static unsigned short def_g[] =
{ 0, 0, 172, 172, 0, 0, 84, 172,
84, 84, 255, 255, 84, 84, 255, 255};
static unsigned short def_b[] =
{ 0, 172, 0, 172, 0, 172, 0, 172,
84, 255, 84, 255, 84, 255, 84, 255};
...
void draw() {
int x, y;
for (y = 0; y < (vinfo.yres / 2); y++) {
for (x = 0; x < vinfo.xres; x++) {
// color based on the 16th of the screen width
int c = 16 * x / vinfo.xres;
// default colors at upper half
put_pixel(x, y, c);
// our own colors at lower half
put_pixel(x, y + (vinfo.yres / 2), c + 16);
}
}
}
...
// in main after opening the fb device
// Set palette
unsigned short r[256];
unsigned short g[256];
unsigned short b[256];
memset(&r, 0, 256); // initialise with zeros
memset(&g, 0, 256);
memset(&b, 0, 256);
int i;
for(i = 0; i < 16; i++) {
// copy the hard-coded values
// note that Linux provides more precision (0-65535),
// so we multiply ours (0-255) by 256
r[i] = def_r[i] << 8;
g[i] = def_g[i] << 8;
b[i] = def_b[i] << 8;
}
struct fb_cmap pal;
pal.start = 16; // start our colors after the default 16
pal.len = 256; // kludge to force bcm fb drv to commit palette...
pal.red = r;
pal.green = g;
pal.blue = b;
pal.transp = 0; // we want all colors non-transparent == null
if (ioctl(fbfd, FBIOPUTCMAP, &pal)) {
printf("Error setting palette.\n");
}
...
</pre>
</div>
...I only hope my monitor color tolerance is about ok and your eyes not much sharper than mine ;)
</div>
<br/>
<div style="text-align: justify;">
Now you could go and fill the palette with any colors you can come up with and draw something interesting. If you use the first 16 color 'slots' in the palette for your own colors, remember to set the default colors at the end of your program:
<div class="code">
<pre>
// before closing the fbfd
// reset palette
palette.start = 0;
palette.len = 256;
palette.red = def_red;
palette.green = def_green;
palette.blue = def_blue;
palette.transp = 0;
if (ioctl(fbfd, FBIOPUTCMAP, &palette)) {
printf("Error setting palette.\n");
}
</pre>
</div>
...otherwise when returning to the console, you might not be able to read any of the text ;) In case this happens (or some other issue with the graphics garbles the screen), one way to fix thing is to type (possibly 'blindly') the commands:
<div class="output">
<pre>
fbset -depth 32
fbset -depth 16
</pre>
</div>
...this (changes the color depth and resets back to the RPi default and) should clear refresh the screen.
</div>
<br/>
<div style="text-align: justify;">
[Continued in <a href="http://raspberrycompote.blogspot.com/2013/03/low-level-graphics-on-raspberry-pi-part_8.html">part six</a>]
</div>
<br/>
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-44241831025111917012013-03-03T15:11:00.001+00:002013-03-03T17:46:29.429+00:00Coding Gold Dust: How to break out from an infinite loop (in Python)<div style="text-align: justify;">
Infinite loops have many uses... In the earlier <a href="http://raspberrycompote.blogspot.ie/2013/02/coding-gold-dust-how-to-write-infinite.html">post</a> I presented a 'Pythonian' way of writing an infinite loop. Obviously in some cases, the loop needs to be 'near infinite' - without the user forcible breaking the execution with <i>Ctrl+C</i>. The simplest way is to use the <span class="codetoken">break</span> command:
<div class="code">
<pre>
while True:
do_something
if some_condition:
break
</pre>
</div>
For example, reading some input from the user ('the oracle answers'):
<div class="code">
<pre>
while True:
s = raw_input("What's your question?")
if s == "who are you":
print "Raspberry Pi!"
if s == "quit":
break
</pre>
</div>
Many other programming languages have the <span class="codetoken">break</span> command as well.
</div>
<br/>
<div style="text-align: justify;">
But if the body of the while loop grows longer - spanning maybe even more than a 'screenful', it might become not so readable anymore. If there are certain defined exit condition(s), why have a <span class="codetoken">while True</span> declaration at all. Wouldn't it be better to tell the reader of the code that there is going to be something breaking out of the loop? For this we can use an exit variable:
<div class="code">
<pre>
done = False
while not done:
s = raw_input("What's your question?")
if s == "who are you":
print "Raspberry Pi!"
if s == "quit":
done = True
</pre>
</div> ...the 'while not done' should read pretty clearly for a human and as <span class="codetoken">not False</span> equals <span class="codetoken">True</span>, the loop runs as long as the variable value is <span class="codetoken">False</span>.
</div>
<br/>
<div style="text-align: justify;">
Of course, there might be multiple such loops in a lengthier program and the exit condition might change. So it should make sense to use an exit variable named to tell what is the actual condition - for example when waiting for a GPIO connected hardware button:
<div class="code">
<pre>
button_pressed = False
while not button_pressed:
# do something
# do something more
button_pressed = read_GPIO_button_press()
</pre>
</div>
And so on... Obviously these are no longer that infinite loops, but well, that's how the question was posed originally ;)
</div>
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-73958806050132317812013-03-03T14:11:00.001+00:002014-04-18T18:40:17.829+01:00Low-level Graphics on Raspberry Pi (part four) <div style="text-align: justify;">
In the <a href="http://raspberrycompote.blogspot.com/2013/01/low-level-graphics-on-raspberry-pi-part_22.html">part three</a> we saw how to plot individual pixels in the framebuffer. Now let's turn the plot-pixel code into a reusable function.</div>
<br/>
<div style="text-align: justify;">
First we need to move some of the variables outside of the <span class="codetoken">main</span> function, so we can access them in the new function - then we just move the pixel plotting code from the main into the new function and make <span class="codetoken">main</span> to call it. We will also move the 'draw' code into another function to separate it from the main and make it easier to read.
<div class="code">
<pre>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
// 'global' variables to store screen info
char *fbp = 0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
// helper function to 'plot' a pixel in given color
void put_pixel(int x, int y, int c)
{
// calculate the pixel's byte offset inside the buffer
unsigned int pix_offset = x + y * finfo.line_length;
// now this is about the same as 'fbp[pix_offset] = value'
*((char*)(fbp + pix_offset)) = c;
}
// helper function for drawing - no more need to go mess with
// the main function when just want to change what to draw...
void draw() {
int x, y;
for (y = 0; y < (vinfo.yres / 2); y++) {
for (x = 0; x < vinfo.xres; x++) {
// color based on the 16th of the screen width
int c = 16 * x / vinfo.xres;
// call the helper function
put_pixel(x, y, c);
}
}
}
// application entry point
int main(int argc, char* argv[])
{
int fbfd = 0;
struct fb_var_screeninfo orig_vinfo;
long int screensize = 0;
// Open the file for reading and writing
fbfd = open("/dev/fb0", O_RDWR);
if (!fbfd) {
printf("Error: cannot open framebuffer device.\n");
return(1);
}
printf("The framebuffer device was opened successfully.\n");
// Get variable screen information
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
printf("Error reading variable information.\n");
}
printf("Original %dx%d, %dbpp\n", vinfo.xres, vinfo.yres,
vinfo.bits_per_pixel );
// Store for reset (copy vinfo to vinfo_orig)
memcpy(&orig_vinfo, &vinfo, sizeof(struct fb_var_screeninfo));
// Change variable info
vinfo.bits_per_pixel = 8;
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo)) {
printf("Error setting variable information.\n");
}
// Get fixed screen information
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
printf("Error reading fixed information.\n");
}
// map fb to user mem
screensize = vinfo.xres * vinfo.yres;
fbp = (char*)mmap(0,
screensize,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fbfd,
0);
if ((int)fbp == -1) {
printf("Failed to mmap.\n");
}
else {
// draw...
draw();
sleep(5);
}
// cleanup
munmap(fbp, screensize);
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo)) {
printf("Error re-setting variable information.\n");
}
close(fbfd);
return 0;
}
</pre>
</div>
Now save the file as <span class="codetoken">fbtest4.c</span>, compile with <span class="codetoken">make fbtest4.c</span> and execute <span class="codetoken">./fbtest4</span> - you should see the same vertical color bars at the upper half of the screen as in part three. Making the <span class="codetoken">put_pixel</span> function should help to come up with new ideas for images to draw...
</div>
<br/>
<div style="text-align: justify;">
[Continued in part <a href="http://raspberrycompote.blogspot.com/2013/03/low-level-graphics-on-raspberry-pi-part_7.html">five</a>]
</div>
Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0tag:blogger.com,1999:blog-5047934568841336576.post-2658367348281614272013-02-05T15:42:00.001+00:002013-02-05T15:55:41.705+00:00Coding Gold Dust: How to write an infinite loop in Python<div style="text-align: justify;">
One of the coding style issues that has come up more than often on the <a href="http://www.raspberrypi.org/phpBB3/index.php">Raspberry Pi forum</a> is: how to write an <a href="http://en.wikipedia.org/wiki/Infinite_loop">infinite loop</a> in <a href="http://en.wikipedia.org/wiki/Python_(programming_language)">Python</a>?
</div>
<br/>
<div style="text-align: justify;">
For obvious reasons, many RPi examples are about hardware or network interfacing, and often these examples are derived from <a href="http://en.wikipedia.org/wiki/C_(programming_language)">C language</a> code. Interfacing, due to it's <a href="http://en.wikipedia.org/wiki/Event-driven_programming">event-driven</a> nature (especially when reading something), warrants the use of an infinite loop - or well, an <a href="http://en.wikipedia.org/wiki/Event_loop">event-loop</a> to be more precise.
</div>
<br/>
<div style="text-align: justify;">
In plain C, there is no <a href="http://en.wikipedia.org/wiki/Boolean_data_type">boolean data type</a> but instead anything 'non zero' evaluates to 'true'. Hence an infinite loop in C is typically (and rightfully so) implemented as a <a href="http://en.wikipedia.org/wiki/While_loop">while loop</a> like this:
<div class="code">
<pre>
while (1) {
printf("Hello, world!\n");
}
</pre>
</div>
</div>
<br/>
<div style="text-align: justify;">
It seems that this does work in Python as well:
<div class="code">
<pre>
while 1:
print "Hello, world!"
</pre>
</div>
</div>
<br/>
<div style="text-align: justify;">
By <a href="http://en.wikipedia.org/wiki/While_loop">definition</a> a while loop continues execution as long as the condition evaluates to true. So practically any expression that evaluates to true <i>could</i> be used:
<div class="code">
<pre>
while (1 == 1):
...
</pre>
</div>
<div class="code">
<pre>
test = "true"
while (test == "true"):
...
</pre>
</div>
<div class="code">
<pre>
while (1 < 2):
...
</pre>
</div>
However, it should be obvious that these are neither <b>beautiful</b>, <b>explicit</b>, <b>simple</b>, <b>readable</b> nor <b>obvious</b> - which are what <a href="http://www.python.org/dev/peps/pep-0020/">'The Zen of Python'</a> lists as 'guiding design principles' for Python, and could be taken as guiding principles for any Python code. In addition, especially the string comparison might incur a performance hit.
</div>
<br/>
<div style="text-align: justify;">
Many programming languages do define proper boolean types. For example Java has a data type called <span class="codetoken">boolean</span> and defines the values <span class="codetoken">true</span> and <span class="codetoken">false</span> for that type. Hence our loop in Java would be:
<div class="code">
<pre>
while (true) {
System.out.println("Hello, world!");
}
</pre>
</div>
Python too defines a class <a href="http://docs.python.org/2/library/functions.html#bool">bool</a>, which can have two values <span class="codetoken">True</span> and <span class="codetoken">False</span>. And because there is a boolean data type, it should make perfect sense to use that and (for consistency) only that to implement an infinite loop:
<div class="code">
<pre>
while True:
print "Hello, world!"
</pre>
</div>
I rest my case ;)
</div>
<br/>
<div style="text-align: justify;">
In addition to The Zen of Python, there is a <a href="http://www.python.org/dev/peps/pep-0008/">Python Style Guide</a> available - definitely worth a read.
</div>
<br/>
<div style="text-align: justify;">P.S. Thanks for fellow RPI forum user alexeames for the idea of <a href="http://www.raspberrypi.org/phpBB3/viewtopic.php?f=32&t=31818&p=275183&hilit=gold+dust#p275183">'Gold Dust'</a> :)</div>
<br/>Anonymoushttp://www.blogger.com/profile/05636267831824524303noreply@blogger.com0