MiniGUI architecture-4. Implementation of image abstraction layer and input abstraction layer and native engine (2)

Source: Internet
Author: User
Tags control characters

3 native graphics engine implementation

Native graphics engine graphics drivers have provided framebuffer-based Drivers Based on Linux kernel. Currently, they support linear 2 bpp, 4bpp, 8bpp, and 16bpp display modes. As we have seen above, most of the interface functions provided by gal are related to graphics. They Call graphics drivers to complete tasks. The graphic driver shields the details of the underlying driver and completes the underlying Driver-related functions, instead of some hardware-related functions, such as some circle and line-drawn GDI functions.

The following describes implementation details based on the implemented framebuffer-based driver. First, the core data structure screendevice is listed. This is mainly for convenience, so some secondary variables or functions are deleted.

Listing 5 native graphics engine core data structure typedef struct _ screendevice {int xres;/* x screen res (real) */INT yres;/* y screen res (real) */INT planes;/* # planes */int bpp;/* # bits per pixel */INT linelen;/* line length in bytes for BPP 1, 2, 4, 8, line Length in pixels for BPP 16, 24, 32 */INT size;/* size of memory allocated */gfx_pixel gr_foreground;/* Current foreground color */gfx_pixel gr_background; /* current background color */INT gr_mode; int flags;/* Device flags */void * ADDR;/* address of memory allocated (memdc or FB) */PSD (* open) (PSD); void (* close) (PSD); void (* setpalette) (PSD, int first, int count, gfx_color * cmap); void (* getpalette) (PSD, int first, int count, gfx_color * cmap); PSD (* allocatememgc) (PSD); bool (* mapmemgc) (PSD mempsd, int W, int H, int planes, int bpp, int linelen, int size, void * ADDR); void (* freemgc) (PSD mempsd ); void (* fillrect) (PSD, int X, int y, int W, int H, gfx_pixel C); void (* drawpixel) (PSD, int X, int y, gfx_pixel C); gfx_pixel (* readpixel) (PSD, int X, int y); void (* drawhline) (PSD, int X, int y, int W, gfx_pixel C); void (* puthline) (Gal gal, int X, int y, int W, void * BUF); void (* gethline) (Gal gal, int X, int y, int W, void * BUF); void (* drawvline) (PSD, int X, int y, int W, gfx_pixel C); void (* putvline) (Gal gal, int X, int y, int W, void * BUF); void (* getvline) (Gal gal, int X, int y, int W, void * BUF); void (* bid) (PSD dstpsd, int dstx, int dsty, int W, int H, PSD srcpsd, int srcx, int srcy ); void (* putbox) (Gal gal, int X, int y, int W, int H, void * BUF); void (* getbox) (Gal gal, int X, int y, int W, int H, void * BUF); void (* putboxmask) (Gal, int X, int y, int W, int H, void * BUF ); void (* copybox) (PSD, int X1, int Y1, int W, int H, int X2, int Y2);} screendevice;

The above PSD is the screendevice pointer, And the gal is the data structure of the GAL interface.

We know that graphic display has a concept of display mode. A pixel can be expressed in one bit, or in 2, 4, 8, 15, 16, 24, and 32 bits. In addition, the standard vga16 mode uses the flat graphics mode, while vesa2.0 uses the linear graphics mode. So even if the framebuffer-based driver is the same, different driver functions should be used in different modes: it is obviously different to draw a 1-bit monochrome point and a 24-bit true color point.

Therefore, graphics drivers use the concept of sub-drivers to support various display modes. In fact, they are the final functional functions. In order to keep the data structure at a level not complex, we use the initial function open of the graphic driver to directly assign the function functions of the sub-driver to the interface function pointer of the graphic driver, after initialization, a simple graphic driver interface is used. Below is the sub-graphics Driver Interface (Listing 6 ).

Listing 6 native graphics engine sub-Driver Interface typedef struct {int (* init) (PSD); void (* drawpixel) (PSD, int X, int y, gfx_pixel C); gfx_pixel (* readpixel) (PSD, int X, int y); void (* drawhline) (PSD, int X, int y, int W, gfx_pixel C); void (* puthline) (Gal gal, int X, int y, int W, void * BUF); void (* gethline) (Gal gal, int X, int y, int W, void * BUF); void (* drawvline) (PSD, int X, int y, int W, gfx_pixel C); void (* putvline) (Gal gal, int X, int y, int W, void * BUF); void (* getvline) (Gal gal, int X, int y, int W, void * BUF); void (* bid) (PSD dstpsd, int dstx, int dsty, int W, int H, PSD srcpsd, int srcx, int srcy ); void (* putbox) (Gal gal, int X, int y, int W, int H, void * BUF); void (* getbox) (Gal gal, int X, int y, int W, int H, void * BUF); void (* putboxmask) (Gal, int X, int y, int W, int H, void * BUF ); void (* copybox) (PSD, int X1, int Y1, int W, int H, int X2, int Y2);} subdriver, * psubdriver;

As you can see, in addition to the init function pointer, other function pointers in this interface are the same as the function pointer in the graphic driver interface. The init function is used to initialize the display mode of the graphic driver.

The following describes the data structure of screendevice, so that you can understand the graphics engine.

A screendevice represents a screen device, which can correspond to a physical screen device or a memory screen device. The existence of memory screen devices mainly aims to improve the quality of GDI, for example, we first store a bitmap in the memory and then draw it on the screen. This gives the user a better visual effect.

First, we will introduce several variables.

  • Xres indicates the screen width (in pixels );
  • Yres indicates the screen height (in pixels );
  • Planes: when it is in the flat display mode, planes is used to record the number of flat planes used, such as the linear mode relative to the flat mode. At this time, this variable is meaningless. Usually set it to 0.
  • BPP: The number of BITs used by each pixel, which can be 1, 2, 4, 8, 15, 16, 24, and 32.
  • Linelen: For each pixel mode of 1, 2, 4, and 8 bits, it indicates the number of bytes used by a row of pixels. For a mode larger than 8 bits per pixel, it indicates the total number of pixels in a row.
  • Size: The number of memories used by the device in this display mode. Linelen and size are mainly used to allocate memory for memory screen devices.
  • Gr_foreground and gr_background: the foreground color and background color of the memory screen, which are mainly used by some GDI functions.
  • Gr_mode: describes how to draw a notebook to the screen. The optional values are mode_set mode_xor mode_or mode_and mode_max. mode_set and mode_xor are commonly used.
  • Flags: some options for the screen device. The more important is the psf_memory mark, indicating that the screen device represents the physical screen device or a memory screen device.
  • ADDR: Each screen device has a memory space for storing pixels. The ADDR variable records the starting address of the space.

The following describes the interface functions:

  • Open, close
  • Basic initialization and termination functions. As mentioned above, you need to select a sub-graphics driver in the open function and assign the implemented function to the function pointer in the PSD structure. Here I will talk about the initialization of the frambebuffer-based graphics engine.

    Fb_open first open the device file/dev/fb0 of framebuffer, and then use IOCTL to read various information about the current framebuffer. Fill in the PSD structure. And select the sub-Driver Based on the information. The program currently supports fbvga16, fblin16, and fblin8, namely, the standard vga16 mode, the VESA linear 16-Bit mode, and the VESA linear 8-Bit mode. Then, place the current terminal mode in the graphic mode. And save some current system information, such as the palette information. Finally, the system uses MMAP to map/dev/fb0 to the memory address. Later, program access to/dev/fb0 will be as simple as accessing an array. Of course, this is for the linear mode. If it is for the plane mode, the problem is much more complicated. From the code point of view, the code in the plane mode is nearly twice the implementation of the linear mode. This problem will be explained in the subsequent difficulties analysis.

  • Setpalette, getpalette
  • The system color palette is used when the 8-bit or below graph mode is used. The color palette processing functions are similar to those in Windows APIs. Linux uses IOCTL to provide an interface for processing the color palette.

  • Allocatememgc, mapmemgc, freemgc
  • I have mentioned the concept of memory screen many times before. The memory screen is a pseudo screen. During operations on the screen image, such as moving the window, we have a memory screen, copy an area of the physical screen to the memory screen and then to the new location of the physical screen. This reduces the latency of Direct Screen Copy. Allocatemgc is used to allocate space to the memory screen. mapmemgc performs initialization, while freemgc releases the memory screen.

  • Drawpixel, readpixel, drawhline, drawvline, fillrect
  • These are underlying graphic functions. They are painting points, reading points, draw horizontal lines, draw vertical lines, and draw a solid rectangle. So many functions are implemented at the underlying layer to improve efficiency. Graphic functions support multiple drawing modes, which are commonly used for direct setting or Alpha hybrid mode, so as to support various graphic effects.

  • Puthline, gethline, putvline, getvline, putbox, getbox, putboxmask
  • The get * function is used to copy pixels from the screen to a memory area, and the put * function is used to draw the pixel stored in the memory area to the screen. The only difference between putboxmask and putbox is that if the pixel to be painted is white, it will not be painted on the screen to achieve a transparent effect.

    We can see from the above that the first parameter of these functions is the gal type rather than the PSD type, because they need information at the gal layer to implement the cut function inside the function. The reason why the cut is not implemented in the upper layer like other functions is because the cut here is special. For example, putbox,

    When cutting the output field, cut the pixels to be output in the buffer at the same time: the pixels beyond the cut field should not be output. Therefore, the cut is not simply the cut of the line, rectangle and other GDI objects. To cut pixels, we need to know the pixel format. These are only for the bottom layer. Therefore, to achieve efficient cutting, we choose to implement them at the bottom layer. All functions here have two parts: Cut, read, and write pixels.

  • BITs, copybox
  • BITs are used to copy a pixel between different screen devices (physical or memory), while copybox is used to copy regional pixels on the same screen. If the linear mode is used, the implementation of BITs is very simple and memcpy can be used directly. To prevent coverage problems, copybox must adopt different copy methods according to different situations, for example, from the bottom to the bottom, when the new and old locations are in the same horizontal position and duplicate, indirect copying using buffering is required. It is complicated to use the flat display mode. Because memory devices always adopt the linear mode, it is necessary to determine whether it is a physical device or a memory device, and then process them separately. This greatly adds the Code implemented by fbvga16.

4 Native input engine implementation

4.1 mouse driver

The mouse driver is very simple. in an abstract sense, after the mouse is initialized, each time you move the mouse, you can get a shift value in the X and Y directions, the driver internally maintains the current mouse position. After the user moves the mouse, the current position is added with a displacement value, which is supported by the upper-layer cursor and reflected on the screen, the user will think that the mouse is "Moved" correctly.

In fact, the implementation of the mouse driver uses the kernel or interfaces provided by other drivers to complete the task. Linux Kernel drivers use device files to abstract most hardware. For example, the PS/2 mouse in our eyes is/dev/psaux. The mouse driver interface is shown in listing 7.

Listing 7 native input engine mouse driver interface typedef struct _ mousedevice {int (* open) (void); void (* close) (void); int (* getbuttoninfo) (void); void (* getdefaaccaccel) (int * pscale, int * pthresh); int (* read) (int * dx, int * dy, int * DZ, int * bp); void (* suspend) (void); void (* resume) (void);} mousedevice;

There are various types of mouse types, such as MS mouse, PS/2 mouse, bus mouse, and GPM mouse. The main difference between them is initialization and data packet format.

For example, it is very easy to open a GPM mouse. You only need to open the device file. When the current terminal is switched to the graphic mode, the GPM Service Program places all the mouse displacement information in the device file.

static int GPM_Open(void)        {        mouse_fd = open(GPM_DEV_FILE, O_NONBLOCK);        if (mouse_fd < 0)        return -1;        return mouse_fd;        }        

For the PS/2 mouse, you must not only open the device file, but also write control characters to the file so that the mouse can start to work.

static int PS2_Open(void)        {        uint8 initdata_ps2[] = { PS2_DEFAULT, PS2_SCALE11, PS2_ENABLE };        mouse_fd = open(PS2_DEV_FILE, O_RDWR | O_NOCTTY | O_NONBLOCK);        if (mouse_fd < 0)        return -1;        write(mouse_fd, initdata_ps2, sizeof(initdata_ps2));        return mouse_fd;        }        

The data packet formats for each mouse are different. In addition, when reading the data, you must first read the data according to the format provided by the kernel driver, but also pay attention to synchronization: each time a header is scanned, the corresponding data can be read, because Microwindows does not have synchronization, in some cases, the mouse will not listen to the "command ".

There is also a concept of "acceleration" in the mouse driver. The program is represented by two variables: Scale and thresh. When the displacement of the mouse exceeds Thresh, It is scaled up. In this way, the final displacement is:

        dx = thresh + (dx - thresh) * scale;        dy = thresh + (dy - thresh) * scale;        

At this point, the mouse driver is quite clear. In the above interface function, getbuttoninfo is used to tell the caller that the mouse supports those buttons. The suspend and resume functions are used to support virtual screen switching, the same is true for the following keyboard drivers.

4.2 keyboard driver

The first problem encountered in implementing the keyboard driver is whether to use the device file/dev/tty or/dev/tty0.

# echo 1 > /dev/tty0        # echo 1 > /dev/tty        

The result will all input 1 to the current terminal. In addition, if you run them on a Pseudo Terminal, the First Command will output 1 to the current terminal on the console, and the second command will output 1 to the current Pseudo Terminal. Tty0 indicates the current console terminal, and tty indicates the current terminal (actually the alias of the current process control terminal ).

The device Number of tty0 is 4, 0

The device Number of tty1 is 5, 0

/Dev/tty is associated with every terminal of the process. What the/dev/tty driver does is to send all requests to the appropriate terminal.

By default,/dev/tty can be read and written by common users, while/dev/tty0 can only be read and written by Super Users, mainly for this reason, we currently use/dev/tty as the device file. All subsequent programs related to terminal processing use it as the current terminal file, which can also be compatible with traditional UNIX.

The keyboard driver interface is shown in listing 8.

Listing 8 native input engine keyboard driver interface typedef struct _ kbddevice {int (* open) (void); void (* close) (void); void (* getmodifierinfo) (int * modifiers); int (* read) (unsigned char * Buf, int * modifiers); void (* suspend) (void); void (* resume) (void);} kbddevice;

The basic principle is very simple. Open/dev/tty during initialization and read all the data from the file later. Because MiniGUI needs to capture key_down and key_up messages, the keyboard is placed in RAW mode. In this way, the program reads the scan code of the keyboard from/dev/tty. For example, if you press the key, you can read 158, put it down, and read 30. In the original mode, the program must write down the States of each key, especially shift, Ctrl, ALT, Caps Lock, etc. Therefore, the Program maintains an array and records the States of all the keyboards.

The following describes how events such as mouse movement and buttons are transmitted to the upper-layer message queue. MiniGUI works in the user state, so it cannot use the efficient mechanism of interruption. Without the support of the kernel driver, it is difficult to use the IPC Mechanism of UNIX systems such as signals. What MiniGUI can do is to check whether/dev/tty,/dev/mouse and other files have data to read. The upper layer tries to read these files by constantly calling gal_waitevent. This is also the main task of thread parser. Gal_waitevent mainly utilizes system calls that are second only to IOCTL in select UNIX systems. And return the waiting event as the return value.

Now we have introduced the keyboard and mouse drivers. As simple input devices, their drivers are very simple. In fact, their implementation code is also relatively small, that is, the touch screen to be used in embedded systems. If the operating system kernel supports it, its driver is also very simple: it is just a special mouse.

5 specific embedded system form engine and input engine implementation

As mentioned above, for Linux-based embedded systems, the kernel generally supports framebuffer, so that the existing native graphics engine can be used. In the MiniGUI code, you can adjust the macro definition in src/GAL/native. h to determine whether the function library contains a specific graphics engine driver (listing 9 ):

Listing 9 defines the native engine sub-driver 16/* define or undefine these macros 17 to include or exclude specific FB driver. 18 */19 # UNDEF _ fblinw.support 20 // # DEFINE _ fblinw.support 1 21 22 # UNDEF _ fblin2_support 23 // # DEFINE _ fblin2_support 1 24 22 # UNDEF _ fblin_2_support 23 //# define _ fblin_2_support 1 24 25 // # UNDEF _ fblin4_support 26 # DEFINE _ fblin4_support 1 27 28 // # UNDEF _ fblin8_support 29 # DEFINE _ fblin8_support 1 30 31 // # UNDEF _ fblin16_support 32 # DEFINE _ fblin16_support 1 33 34 # UNDEF _ fblin24_support 35 // # DEFINE _ fblin24_support 1 36 37 # UNDEF _ fblin32_support 38 // # DEFINE _ fblin32_support 1 39 40 # define havetextmode 1 /* = 0 for graphics only Systems */

Havetextmode defines whether the system has the text mode. You can block the code used in MiniGUI to disable the text mode. _ Fblin_2_support and _ fblin2_support are used to define the 2bpp drivers for big endian and little endian respectively.

For the input engine, the situation is somewhat different. At present, there is no unified interface for processing output devices, and the input devices of each embedded system are also different. Therefore, we usually need to re-enter the engine for a specific embedded system. The following code is an input engine written for the ads Embedded Development System Based on strongarm (List 10 ):

Listing 10 is the input engine 30 31 # include <stdio. h> 32 # include <stdlib. h> 33 # include <string. h> 34 # include <unistd. h> 35 # include <sys/Io. h> 36 # include <sys/IOCTL. h> 37 # include <sys/poll. h> 38 # include <Linux/KD. h> 39 # include <sys/types. h> 40 # include <sys/STAT. h> 41 # include <fcntl. h> 42 43 # include "Common. H "44 # include" Misc. H "45 # include" ads_internal.h "46 # include" ial. H "47 # include" ads. H "48 49 # ifndef nr_keys 50 # define nr_keys 128 51 # endif 52 53 static int ts; 54 static int mousex = 0; 55 static int Mousey = 0; 56 static POS Pos; 57 58 static unsigned char State [nr_keys]; 59 60/************************ low level input operations ********* * ***********/61/* 62 * mouse operations -- event 63 */64 static int mouse_update (void) 65 {66 return 0; 67} 68 6 9 static int mouse_getx (void) 70 {71 return mousex; 72} 73 74 static int mouse_gety (void) 75 {76 return Mousey; 77} 78 79 static void mouse_setposition (int x, int y) 80 {81} 82 83 static int mouse_getbutton (void) 84 {85 return POS. b; 86} 87 88 static void mouse_setrange (INT Minx, int miny, int Maxx, int Maxy) 89 {90} 91 92 static int keyboard_update (void) 93 {94 return 0; 95} 96 97 static Char * keyboard_getstate (void) 98 {99 return (char *) State; 100} 101 102 103 # ifdef _ lite_version static int wait_event (INT which, int maxfd, fd_set * In, fd_set * Out, fd_set * struct T, 104 struct timeval * timeout) 105 {106 fd_set rfds; 107 int e; 108 109 If (! In) {110 in = & rfds; 111 fd_zero (in); 112} 113 114 If (which & ial_mouseevent) {115 fd_set (TS, In ); 116 If (TS> maxfd) maxfd = ts; 117} 118 E = select (maxfd + 1, in, out, timeout T, timeout); 119 120 If (E> 0) {122 If (TS> = 0 & fd_isset (TS, In) 123 {124 fd_clr (TS, In); 125 read (TS, & Pos, sizeof (POS); 126 If (POS. x! =-1 & Pos. y! =-1) {127 mousex = pos. X; 128 Mousey = pos. Y; 129} 130 pos. B = (Pos. B> 0? 4: 0); 131 return ial_mouseevent; 132} 133 134} else if (E <0) {135 return-1; 136} 137 return 0; 138} 139 # else 140 static int wait_event (INT which, fd_set * In, fd_set * Out, fd_set * handle T, 141 struct timeval * timeout) 142 {143 struct pollfd UFD; 144 if (which & ial_mouseevent) = ial_mouseevent) 145 {146 UFD. FD = ts; 147 UFD. events = Pollin; 148 If (poll (& UFD, 1, timeout)> 0) 149 {150 read (TS, & Pos, sizeof (POS); 151 return ial_mouseevent; 152} 153} 154 return 0; 155} 156 # endif 157 158 static void set_leds (unsigned int LEDs) 159 {160} 161 bool initadsinput (input * input, const char * mdev, const char * mtype) 163 {164 int I; 165 166 Ts = open ("/dev/ts", o_rdonly); 167 If (TS <0) {168 fprintf (stderr, "ial: can not open touch screen! \ N "); 169 return false; 170} 171 172 for (I = 0; I <nr_keys; I ++) 173 State [I] = 0; 174 175 input-> update_mouse = mouse_update; 176 input-> get_mouse_x = mouse_getx; 177 input-> get_mouse_y = mouse_gety; 178 input-> set_mouse_xy = mouse_setposition; 179 input-> get_mouse_button = mouse_getbutton; 180 input-> set_mouse_range = mouse_setrange; 181 182 input-> update_keyboard = keyboard_update; 183 input-> get_keyboard_state = keyboard_getstate; 184 input-> set_leds = set_leds; 185 186 input-> wait_event = wait_event; 187 mousex = 0; 188 Mousey = 0; 189 return true; 190} 191 void termadsinput (void) 193 {194 If (TS> = 0) 195 close (TS); 196} 197

In the above input engine, keyboard-related function implementation is completely ignored, and the code is concentrated on the processing of touch screens. Obviously, writing the input engine is not very difficult.

6 Summary

This article introduces the gal and ial interfaces of MiniGUI in detail. Taking the native graphics engine and input engine as an example, it introduces the implementation of the specific graphics engine and input engine. Of course, there are still many shortcomings in the current gal and ial interfaces of MiniGUI, such as the low degree of coupling with upper-layer GDI, which may cause some loss of efficiency. In future development of MiniGUI, We will redesign the GDI and underlying graphic engine interfaces to optimize the window system.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.