Now that we have been gradually building the example program to allow us to do something interesting - how about trying a bit of animation?
Save as fbtestX.c (complete code in GitHub) - build with make fbtestX. 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 tearing effect.
... // 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... } } ...
Linux framebuffer interface does define some methods to overcome this - we could make the framebuffer virtual size double the height of the (smaller) physical one using the FBIOPUT_VSCREENINFO call:
And change our drawing loop to use the two halves of the virtual buffer using a call to FBIOPAN_DISPLAY for page-flipping tied to a vertical sync using FB_ACTIVATE_VBL:
Unfortunately these calls have not been implemented in the RPi framebuffer driver (does not seem to be in later versions either yet, see also http://www.raspberrypi.org/phpBB3/viewtopic.php?f=67&t=19073). So running the above code (full code) results in repeated output of Error panning display. and the rectangle flashing even worse (as we miss every second screen update by drawing outside of the visible area).
// 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;
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"); } }
[Continued in next part]
[UPDATE on changes in the fb driver here]
Switching the ioctl(fbfd, FBIOPAN_DISPLAY, &vinfo) to ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo) seems to work slightly better - it does flip the page to the yoffset, but unfortunately it also redraws the console buffer, so one may end up with flashing directory listing or whatever was on display when starting the tester app...
ReplyDelete