The Vybrid Display Controller Unit (DCU4) module is a bus master that fetches graphics stored in internal or external memory and displays them on a TFT LCD panel. Graphics are read directly from memory and then blended in real-time, which allows for dynamic content creation with minimal CPU intervention. Users control the graphical content of the TFT panel by manipulating the configuration of elements in the DCU4 called layers.
Starting with v2.3 Beta5 the Vybrid framebuffer driver provides the following features:
The Vyrbid framebuffer driver provides five framebuffer nodes. The framebuffer nodes have a fixed priority. fb0 has the highest priority and fb5 the lowest. This priority controls how the image which has been rendered on different layers, interact with each other as per the alpha value and this priority, in giving a blended image. fb0 having the highest priority with an alpha value of 255 results in the content drawn on other framebuffer nodes to be opaque. Setting an alpha value different then 255 will allow the content drawn on other layers to be visible and transparent depending on the alpha value of the said layer in question.
Note: Currently, the driver uses multiple framebuffer (fbX) device nodes to export this functionality. In the future, this functionality will probably be exported using planes through the more modern KMS/DRM interface.
The sample code below uses the ioctl() calls provided by the driver to change the alpha value and bits per pixel setting. There is also a function to change and set the layers content X and Y axis offset for completion sake. To set the alpha or bits per pixel value for a node, open the said fb node and then use set alpha and set bits per pixel functionality.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <linux/types.h> #include <linux/ioctl.h> #include <linux/fb.h> #include <sys/mman.h> #include <cairo/cairo.h> /* Refer drivers/video/fbdev/fsl-dcu-fb.c */ #define MFB_SET_ALPHA _IOW('M', 0, __u8) #define MFB_GET_ALPHA _IOR('M', 0, __u8) #define MFB_SET_LAYER _IOW('M', 4, struct layer_display_offset) #define MFB_GET_LAYER _IOR('M', 4, struct layer_display_offset) #define GET_LAYER 1 #define SET_LAYER 2 #define GET_ALPHA 3 #define SET_ALPHA 4 #define SET_BITS_PER_PIXEL 5 #define GET_SCREENINFO 6 #define EXIT 7 /* Refer drivers/video/fbdev/fsl-dcu-fb.c */ struct layer_display_offset { int x_layer_d; int y_layer_d; }; /* * Refer struct mfb_info in drivers/video/fbdev/fsl-dcu-fb.c * Layer 0: x_layer_d = 0; y_layer_d = 0, * Layer 1: x_layer_d = 50; y_layer_d = 50 * Layer 2: x_layer_d = 100; y_layer_d = 100 * Layer 3: x_layer_d = 150; y_layer_d = 150 * Layer 4: x_layer_d = 200; y_layer_d = 200 * Layer 5: x_layer_d = 250; y_layer_d = 250 */ int main(void) { int fd; int ret; int choice; int layer_number; int bits_per_pixel; char frame_buffer_number; char fb_node[16] = {0}; unsigned char alpha; struct layer_display_offset data; struct fb_var_screeninfo vscreeninfo; printf("Enter frame buffer number(0-5):\t"); scanf("%c", &frame_buffer_number); sprintf(fb_node, "/dev/fb"); fb_node[strlen(fb_node)] = frame_buffer_number; fb_node[strlen(fb_node)] = '\0'; printf("Frame buffer node is: %s\n", fb_node); fd = open(fb_node, O_RDWR); if (fd < 0) { perror("Error"); return -1; } while (1) { printf("\n1. Get layer\n"); printf("2. Set layer\n"); printf("3. Get alpha value\n"); printf("4. Set alpha value\n"); printf("5. Set bits per pixel\n"); printf("6. Get screen information\n"); printf("7. Exit\n"); printf("\nEnter your choice (1-7):\t"); scanf("%d[0-7]", &choice); switch(choice) { case GET_LAYER: ret = ioctl(fd, MFB_GET_LAYER, &data); if (ret) perror("Error"); else if (data.x_layer_d == 0 && data.y_layer_d == 0) printf("Current layer is 0\n"); else if (data.x_layer_d == 50 && data.y_layer_d == 50) printf("Current layer is 1\n"); else if (data.x_layer_d == 100 && data.y_layer_d == 100) printf("Current layer is 2\n"); else if (data.x_layer_d == 150 && data.y_layer_d == 150) printf("Current layer is 3\n"); else if (data.x_layer_d == 200 && data.y_layer_d == 200) printf("Current layer is 4\n"); else if (data.x_layer_d == 250 && data.y_layer_d == 250) printf("Currnet layer is 5\n"); break; case SET_LAYER: layer_number = -1; printf("Enter the layer number(0-5) to set:\t"); scanf("%d", &layer_number); switch (layer_number) { case 0: data.x_layer_d = 0; data.y_layer_d = 0; break; case 1: data.x_layer_d = 50; data.y_layer_d = 50; break; case 2: data.x_layer_d = 100; data.y_layer_d = 100; break; case 3: data.x_layer_d = 150; data.y_layer_d = 150; break; case 4: data.x_layer_d = 200; data.y_layer_d = 200; break; case 5: data.x_layer_d = 250; data.y_layer_d = 250; break; default: layer_number = -1; printf("Invalid layer number\n"); break; } if (layer_number != -1) { ret = ioctl(fd, MFB_SET_LAYER, &data); if (ret) perror("Error"); else printf("Layer set successfully\n"); } break; case GET_ALPHA: alpha = -1; ret = ioctl(fd, MFB_GET_ALPHA, &alpha); if (ret) perror("Error"); else printf("Alpha value is: %d\n", alpha); break; case SET_ALPHA: printf("Enter the value of alpha to set:\t"); scanf("%d", &alpha); ret = ioctl(fd, MFB_SET_ALPHA, &alpha); if (ret) perror("Error"); else printf("Alpha value set\n"); break; case SET_BITS_PER_PIXEL: printf("\nEnter the value of bits per pixel:\t"); scanf("%d", &bits_per_pixel); vscreeninfo.bits_per_pixel = bits_per_pixel; ret = ioctl(fd, FBIOPUT_VSCREENINFO, &vscreeninfo); if (ret) perror("Error"); else printf("Bits per pixel set\n"); break; case GET_SCREENINFO: ret = ioctl(fd, FBIOGET_VSCREENINFO, &vscreeninfo); if (ret) perror("Error"); else { printf("\nVscreen Info:-\n"); printf(" Xres = %4ld | Yres = %4ld\n", vscreeninfo.xres,vscreeninfo.yres); printf(" BPP = %4ld | Height = %4ld | Width = %4ld\n", vscreeninfo.bits_per_pixel, vscreeninfo.height, vscreeninfo.width); printf(" Xres_V = %4ld | Yres_V = %4ld\n", vscreeninfo.height,vscreeninfo.width); printf(" Pixel format : RGBX_%ld%ld%ld%ld\n", vscreeninfo.red.length, vscreeninfo.green.length, vscreeninfo.blue.length, vscreeninfo.transp.length); printf(" Begin of bitfields(Byte ordering):-\n"); printf(" Red : %ld\n", vscreeninfo.red.offset); printf(" Blue : %ld\n", vscreeninfo.blue.offset); printf(" Green : %ld\n", vscreeninfo.green.offset); printf(" Transp : %ld\n", vscreeninfo.transp.offset); } break; case EXIT: close(fd); exit(0); break; default: printf("Invalid choice\n"); choice = -1; break; } } }
The above source code can be downloaded from here. Below is the Makefile which can be used for building the above example code with make fbdev. The sysroot, INCLUDES and LIB_PATH in the below Makefile need to be modified to either point to the relevant path in your OpenEmbedded setup or path in the extracted image archive for Vybrid.
CC = ${HOME}/gcc-linaro/bin/arm-linux-gnueabihf-gcc INCLUDES = "-I${HOME}/oe-core/build/out-glibc/sysroots/colibri-vf/usr/include" LIB_PATH = "-L${HOME}/oe-core/build/out-glibc/sysroots/colibri-vf/usr/lib" CFLAGS = -O2 -g -mfloat-abi=hard --sysroot=${HOME}/oe-core/build/out-glibc/sysroots/colibri-vf/ fbdev: ${CC} ${CFLAGS} ${INCLUDES} ${LIB_PATH} ${LDFLAGS} -o fbdev fbdev.c clean: rm -rf fbdev
This can be used with the Cairo sample program to test alpha blending. The above code can be used to set the alpha value and bits per pixel setting for a layer while a Cairo library based application can be used for writing to the framebuffer. For Cairo, please note the fact that the bits per pixel setting for a layer needs to be 32 while using CAIRO_FORMAT_RGB24.
root@colibri-vf:~# ./fbdev Enter frame buffer number(0-5): 0 Frame buffer node is: /dev/fb0 1. Get layer 2. Set layer 3. Get alpha value 4. Set alpha value 5. Set bits per pixel 6. Get screen information 7. Exit Enter your choice (1-7): 4 Enter the value of alpha to set: 150 Alpha value set 1. Get layer 2. Set layer 3. Get alpha value 4. Set alpha value 5. Set bits per pixel 6. Get screen information 7. Exit Enter your choice (1-7): 7
Note that the LXDE running on X-Server is running on fb0. The Cairo example will use fb1:
root@colibri-vf:~# ./cairo arch_sh-600x600.png Enter frame buffer number: 1 Frame buffer node is: /dev/fb1
The above sample run gives a result as below. Depending on the alpha value set for fb0 and fb1 the results of the blending can be controlled.
root@colibri-vf:~# ./fbdev Enter frame buffer number(0-5): 0 Frame buffer node is: /dev/fb0 1. Get layer 2. Set layer 3. Get alpha value 4. Set alpha value 5. Set bits per pixel 6. Get screen information 7. Exit Enter your choice (1-7): 4 Enter the value of alpha to set: 0 Alpha value set 1. Get layer 2. Set layer 3. Get alpha value 4. Set alpha value 5. Set bits per pixel 6. Get screen information 7. Exit Enter your choice (1-7): 7
root@colibri-vf:~# ./cairo arch_sh-600x600.png Enter frame buffer number: 1 Frame buffer node is: /dev/fb1 root@colibri-vf:~#
The above options give results as shown in the pictures below. The alpha value of fb0 has been set to 0 here, the fb0 layer shows up as complete black. The actual colours of the image drawn by Cairo on fb1 are now clear, due to the absence of blending effect with fb0. For the text in the left image, the RGB value was 110 respectively which was specified with Cairo. In this example, this text shows up clearly in yellow colour with only the red and green component being present, while the same text in the previous example has a different result, due to the blending effect (depending on the alpha values of fb0 and fb1).
root@colibri-vf:~# ./fbdev Enter frame buffer number(0-5): 0 Frame buffer node is: /dev/fb0 1. Get layer 2. Set layer 3. Get alpha value 4. Set alpha value 5. Set bits per pixel 6. Get screen information 7. Exit Enter your choice (1-7): 4 Enter the value of alpha to set: 128 Alpha value set 1. Get layer 2. Set layer 3. Get alpha value 4. Set alpha value 5. Set bits per pixel 6. Get screen information 7. Exit Enter your choice (1-7): 7
root@colibri-vf:~# ./cairo dice.png Enter frame buffer number: 0 Frame buffer node is: /dev/fb0 root@colibri-vf:~#
The image for the above and subsequent example was generated by mapping the framebuffer console to fb1 with fbcon=map:1 and then writing to fb0 with the Cairo sample.
root@colibri-vf:~# ./fbdev Enter frame buffer number(0-5): 0 Frame buffer node is: /dev/fb0 1. Get layer 2. Set layer 3. Get alpha value 4. Set alpha value 5. Set bits per pixel 6. Get screen information 7. Exit Enter your choice (1-7): 5 Enter the value of bits per pixel: 32 Bits per pixel set 1. Get layer 2. Set layer 3. Get alpha value 4. Set alpha value 5. Set bits per pixel 6. Get screen information 7. Exit Enter your choice (1-7): 7
The Cairo sample uses CAIRO_FORMAT_ARGB32 as pixel format. The dice picture in the PNG file format uses transparency, which in turn is supported and transferred to the Framebuffer device by Cairo.
root@colibri-vf:~# ./cairo dice.png Enter frame buffer number: 0 Frame buffer node is: /dev/fb0 root@colibri-vf:~#
Please refer the Vybrid frambuffer driver and the Section 55.5.4 Layer configuration and blending in the Vybrid Reference Manual which can be downloaded from here for more information.