22
22
#define FBDEV_DEFAULT "/dev/fb0"
23
23
#define SCREEN (x ) ((twin_context_t *) x)->screen
24
24
#define PRIV (x ) ((twin_fbdev_t *) ((twin_context_t *) x)->priv)
25
+ #define ARGB32_TO_RGB565 (pixel ) \
26
+ (((pixel & 0x00f80000) >> 8) | ((pixel & 0x0000fc00) >> 5) | \
27
+ ((pixel & 0x000000f8) >> 3))
28
+
29
+ /* Requires validation in 24-bit per pixel environments. */
30
+ #define ARGB32_TO_RGB888 (pixel ) (0xff000000 | (pixel))
31
+ #define GET_TWIN_FBDEV (left , top , closure , dest ) \
32
+ do { \
33
+ twin_screen_t *screen = SCREEN(closure); \
34
+ twin_fbdev_t *tx = PRIV(closure); \
35
+ off_t off = (top) * (screen->width) + (left); \
36
+ *(dest) = \
37
+ (uint32_t *) ((uintptr_t) tx->fb_base + (off * sizeof(uint32_t))); \
38
+ } while (0)
25
39
26
40
typedef struct {
27
41
twin_screen_t * screen ;
@@ -43,22 +57,43 @@ typedef struct {
43
57
size_t fb_len ;
44
58
} twin_fbdev_t ;
45
59
46
- static void _twin_fbdev_put_span (twin_coord_t left ,
47
- twin_coord_t top ,
48
- twin_coord_t right ,
49
- twin_argb32_t * pixels ,
50
- void * closure )
60
+ static void _twin_fbdev_put_span16 (twin_coord_t left ,
61
+ twin_coord_t top ,
62
+ twin_coord_t right ,
63
+ twin_argb32_t * pixels ,
64
+ void * closure )
51
65
{
52
- twin_screen_t * screen = SCREEN (closure );
53
- twin_fbdev_t * tx = PRIV (closure );
66
+ uint32_t * dest ;
67
+ GET_TWIN_FBDEV (left , top , closure , & dest );
68
+ twin_coord_t width = right - left ;
69
+ for (int i = 0 ; i < width ; i ++ ) {
70
+ dest [i ] = ARGB32_TO_RGB565 (pixels [i ]);
71
+ }
72
+ }
54
73
55
- if (tx -> fb_base == MAP_FAILED )
56
- return ;
74
+ static void _twin_fbdev_put_span24 (twin_coord_t left ,
75
+ twin_coord_t top ,
76
+ twin_coord_t right ,
77
+ twin_argb32_t * pixels ,
78
+ void * closure )
79
+ {
80
+ uint32_t * dest ;
81
+ GET_TWIN_FBDEV (left , top , closure , & dest );
82
+ twin_coord_t width = right - left ;
83
+ for (int i = 0 ; i < width ; i ++ ) {
84
+ dest [i ] = ARGB32_TO_RGB888 (pixels [i ]);
85
+ }
86
+ }
57
87
88
+ static void _twin_fbdev_put_span32 (twin_coord_t left ,
89
+ twin_coord_t top ,
90
+ twin_coord_t right ,
91
+ twin_argb32_t * pixels ,
92
+ void * closure )
93
+ {
94
+ uint32_t * dest ;
95
+ GET_TWIN_FBDEV (left , top , closure , & dest );
58
96
twin_coord_t width = right - left ;
59
- off_t off = top * screen -> width + left ;
60
- uint32_t * dest =
61
- (uint32_t * ) ((uintptr_t ) tx -> fb_base + (off * sizeof (* dest )));
62
97
memcpy (dest , pixels , width * sizeof (* dest ));
63
98
}
64
99
@@ -88,6 +123,27 @@ static bool twin_fbdev_work(void *closure)
88
123
return true;
89
124
}
90
125
126
+ static bool twin_fbdev_is_rgb565 (twin_fbdev_t * tx )
127
+ {
128
+ return tx -> fb_var .red .offset == 11 && tx -> fb_var .red .length == 5 &&
129
+ tx -> fb_var .green .offset == 5 && tx -> fb_var .green .length == 6 &&
130
+ tx -> fb_var .blue .offset == 0 && tx -> fb_var .blue .length == 5 ;
131
+ }
132
+
133
+ static bool twin_fbdev_is_rgb888 (twin_fbdev_t * tx )
134
+ {
135
+ return tx -> fb_var .red .offset == 16 && tx -> fb_var .red .length == 8 &&
136
+ tx -> fb_var .green .offset == 8 && tx -> fb_var .green .length == 8 &&
137
+ tx -> fb_var .blue .offset == 0 && tx -> fb_var .blue .length == 8 ;
138
+ }
139
+
140
+ static bool twin_fbdev_is_argb32 (twin_fbdev_t * tx )
141
+ {
142
+ return tx -> fb_var .red .offset == 16 && tx -> fb_var .red .length == 8 &&
143
+ tx -> fb_var .green .offset == 8 && tx -> fb_var .green .length == 8 &&
144
+ tx -> fb_var .blue .offset == 0 && tx -> fb_var .blue .length == 8 ;
145
+ }
146
+
91
147
static bool twin_fbdev_apply_config (twin_fbdev_t * tx )
92
148
{
93
149
/* Read changable information of the framebuffer */
@@ -111,10 +167,29 @@ static bool twin_fbdev_apply_config(twin_fbdev_t *tx)
111
167
return false;
112
168
}
113
169
114
- /* Check bits per pixel */
115
- if (tx -> fb_var .bits_per_pixel != 32 ) {
116
- log_error ("Failed to set framebuffer bpp to 32" );
117
- return false;
170
+ /* Examine the framebuffer format */
171
+ switch (tx -> fb_var .bits_per_pixel ) {
172
+ case 16 : // RGB565
173
+ if (!twin_fbdev_is_rgb565 (tx )) {
174
+ log_error ("Invalid framebuffer format for 16 bpp" );
175
+ return false;
176
+ }
177
+ break ;
178
+ case 24 : // RGB888
179
+ if (!twin_fbdev_is_rgb888 (tx )) {
180
+ log_error ("Invalid framebuffer format for 24 bpp" );
181
+ return false;
182
+ }
183
+ break ;
184
+ case 32 : // ARGB32
185
+ if (!twin_fbdev_is_argb32 (tx )) {
186
+ log_error ("Invalid framebuffer format for 32 bpp" );
187
+ return false;
188
+ }
189
+ break ;
190
+ default :
191
+ log_error ("Unsupported bits per pixel: %d" , tx -> fb_var .bits_per_pixel );
192
+ break ;
118
193
}
119
194
120
195
/* Read unchangable information of the framebuffer */
@@ -220,9 +295,20 @@ twin_context_t *twin_fbdev_init(int width, int height)
220
295
goto bail_vt_fd ;
221
296
}
222
297
298
+ /* Examine if framebuffer mapping is valid */
299
+ if (tx -> fb_base == MAP_FAILED ) {
300
+ log_error ("Failed to map framebuffer memory" );
301
+ return ;
302
+ }
303
+
223
304
/* Create TWIN screen */
224
- ctx -> screen =
225
- twin_screen_create (width , height , NULL , _twin_fbdev_put_span , ctx );
305
+ ctx -> screen = twin_screen_create (
306
+ width , height , NULL ,
307
+ (tx -> fb_var .bits_per_pixel == 16 ) ? _twin_fbdev_put_span16
308
+ : (tx -> fb_var .bits_per_pixel == 24 ) ? _twin_fbdev_put_span24
309
+ : (tx -> fb_var .bits_per_pixel == 32 ) ? _twin_fbdev_put_span32
310
+ : NULL ,
311
+ ctx );
226
312
227
313
/* Create Linux input system object */
228
314
tx -> input = twin_linux_input_create (ctx -> screen );
0 commit comments