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 inline 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 inline 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 inline 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 */
@@ -99,7 +155,6 @@ static bool twin_fbdev_apply_config(twin_fbdev_t *tx)
99
155
/* Set the virtual screen size to be the same as the physical screen */
100
156
tx -> fb_var .xres_virtual = tx -> fb_var .xres ;
101
157
tx -> fb_var .yres_virtual = tx -> fb_var .yres ;
102
- tx -> fb_var .bits_per_pixel = 32 ;
103
158
if (ioctl (tx -> fb_fd , FBIOPUT_VSCREENINFO , & tx -> fb_var ) < 0 ) {
104
159
log_error ("Failed to set framebuffer mode" );
105
160
return false;
@@ -111,10 +166,29 @@ static bool twin_fbdev_apply_config(twin_fbdev_t *tx)
111
166
return false;
112
167
}
113
168
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;
169
+ /* Examine the framebuffer format */
170
+ switch (tx -> fb_var .bits_per_pixel ) {
171
+ case 16 : /* RGB565 */
172
+ if (!twin_fbdev_is_rgb565 (tx )) {
173
+ log_error ("Invalid framebuffer format for 16 bpp" );
174
+ return false;
175
+ }
176
+ break ;
177
+ case 24 : /* RGB888 */
178
+ if (!twin_fbdev_is_rgb888 (tx )) {
179
+ log_error ("Invalid framebuffer format for 24 bpp" );
180
+ return false;
181
+ }
182
+ break ;
183
+ case 32 : /* ARGB32 */
184
+ if (!twin_fbdev_is_argb32 (tx )) {
185
+ log_error ("Invalid framebuffer format for 32 bpp" );
186
+ return false;
187
+ }
188
+ break ;
189
+ default :
190
+ log_error ("Unsupported bits per pixel: %d" , tx -> fb_var .bits_per_pixel );
191
+ break ;
118
192
}
119
193
120
194
/* Read unchangable information of the framebuffer */
@@ -220,9 +294,20 @@ twin_context_t *twin_fbdev_init(int width, int height)
220
294
goto bail_vt_fd ;
221
295
}
222
296
297
+ /* Examine if framebuffer mapping is valid */
298
+ if (tx -> fb_base == MAP_FAILED ) {
299
+ log_error ("Failed to map framebuffer memory" );
300
+ return ;
301
+ }
302
+
223
303
/* Create TWIN screen */
224
- ctx -> screen =
225
- twin_screen_create (width , height , NULL , _twin_fbdev_put_span , ctx );
304
+ ctx -> screen = twin_screen_create (
305
+ width , height , NULL ,
306
+ (tx -> fb_var .bits_per_pixel == 16 ) ? _twin_fbdev_put_span16
307
+ : (tx -> fb_var .bits_per_pixel == 24 ) ? _twin_fbdev_put_span24
308
+ : (tx -> fb_var .bits_per_pixel == 32 ) ? _twin_fbdev_put_span32
309
+ : NULL ,
310
+ ctx );
226
311
227
312
/* Create Linux input system object */
228
313
tx -> input = twin_linux_input_create (ctx -> screen );
0 commit comments