2 * Mesa 3-D graphics library
5 * Copyright (C) 2010 LunarG Inc.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
26 * Chia-I Wu <olv@lunarg.com>
30 * Considering fbdev as an in-kernel window system,
32 * - opening a device opens a connection
33 * - there is only one window: the framebuffer
34 * - fb_var_screeninfo decides window position, size, and even color format
35 * - there is no pixmap
37 * Now EGL is built on top of this window system. So we should have
39 * - the fd as the handle of the native display
40 * - reject all but one native window: NULL
44 #include <sys/ioctl.h>
45 #include <sys/types.h>
50 #include "pipe/p_screen.h"
51 #include "util/u_memory.h"
52 #include "util/u_inlines.h"
53 #include "util/u_pointer.h"
55 #include "common/native.h"
56 #include "common/native_helper.h"
57 #include "fbdev/fbdev_sw_winsys.h"
59 struct fbdev_display
{
60 struct native_display base
;
63 const struct native_event_handler
*event_handler
;
65 struct fb_fix_screeninfo finfo
;
66 struct fb_var_screeninfo config_vinfo
;
67 struct native_config config
;
69 boolean assume_fixed_vinfo
;
72 struct fbdev_surface
{
73 struct native_surface base
;
75 struct fbdev_display
*fbdpy
;
76 struct resource_surface
*rsurf
;
79 unsigned int sequence_number
;
81 struct fbdev_sw_drawable drawable
;
84 static INLINE
struct fbdev_display
*
85 fbdev_display(const struct native_display
*ndpy
)
87 return (struct fbdev_display
*) ndpy
;
90 static INLINE
struct fbdev_surface
*
91 fbdev_surface(const struct native_surface
*nsurf
)
93 return (struct fbdev_surface
*) nsurf
;
97 fbdev_surface_validate(struct native_surface
*nsurf
, uint attachment_mask
,
98 unsigned int *seq_num
, struct pipe_resource
**textures
,
99 int *width
, int *height
)
101 struct fbdev_surface
*fbsurf
= fbdev_surface(nsurf
);
103 if (!resource_surface_add_resources(fbsurf
->rsurf
, attachment_mask
))
106 resource_surface_get_resources(fbsurf
->rsurf
, textures
, attachment_mask
);
109 *seq_num
= fbsurf
->sequence_number
;
111 *width
= fbsurf
->width
;
113 *height
= fbsurf
->height
;
118 static enum pipe_format
119 vinfo_to_format(const struct fb_var_screeninfo
*vinfo
)
121 enum pipe_format format
= PIPE_FORMAT_NONE
;
123 /* should also check channel offsets... */
124 switch (vinfo
->bits_per_pixel
) {
126 if (vinfo
->red
.length
== 8 &&
127 vinfo
->green
.length
== 8 &&
128 vinfo
->blue
.length
== 8) {
129 format
= (vinfo
->transp
.length
== 8) ?
130 PIPE_FORMAT_B8G8R8A8_UNORM
: PIPE_FORMAT_B8G8R8X8_UNORM
;
134 if (vinfo
->red
.length
== 5 &&
135 vinfo
->green
.length
== 6 &&
136 vinfo
->blue
.length
== 5 &&
137 vinfo
->transp
.length
== 0)
138 format
= PIPE_FORMAT_B5G6R5_UNORM
;
148 fbdev_surface_update_drawable(struct native_surface
*nsurf
,
149 const struct fb_var_screeninfo
*vinfo
)
151 struct fbdev_surface
*fbsurf
= fbdev_surface(nsurf
);
152 unsigned x
, y
, width
, height
;
156 width
= MIN2(vinfo
->xres
, fbsurf
->width
);
157 height
= MIN2(vinfo
->yres
, fbsurf
->height
);
159 /* sanitize the values */
160 if (x
+ width
> vinfo
->xres_virtual
) {
161 if (x
> vinfo
->xres_virtual
)
164 width
= vinfo
->xres_virtual
- x
;
166 if (y
+ height
> vinfo
->yres_virtual
) {
167 if (y
> vinfo
->yres_virtual
)
170 height
= vinfo
->yres_virtual
- y
;
173 fbsurf
->drawable
.format
= vinfo_to_format(vinfo
);
174 fbsurf
->drawable
.x
= vinfo
->xoffset
;
175 fbsurf
->drawable
.y
= vinfo
->yoffset
;
176 fbsurf
->drawable
.width
= vinfo
->xres
;
177 fbsurf
->drawable
.height
= vinfo
->yres
;
179 return (fbsurf
->drawable
.format
!= PIPE_FORMAT_NONE
&&
180 fbsurf
->drawable
.width
&&
181 fbsurf
->drawable
.height
);
185 fbdev_surface_present(struct native_surface
*nsurf
,
186 enum native_attachment natt
,
190 struct fbdev_surface
*fbsurf
= fbdev_surface(nsurf
);
191 struct fbdev_display
*fbdpy
= fbsurf
->fbdpy
;
196 if (natt
!= NATIVE_ATTACHMENT_BACK_LEFT
)
199 if (!fbdpy
->assume_fixed_vinfo
) {
200 struct fb_var_screeninfo vinfo
;
202 memset(&vinfo
, 0, sizeof(vinfo
));
203 if (ioctl(fbdpy
->fd
, FBIOGET_VSCREENINFO
, &vinfo
))
206 /* present the surface */
207 if (fbdev_surface_update_drawable(&fbsurf
->base
, &vinfo
)) {
208 ret
= resource_surface_present(fbsurf
->rsurf
,
209 natt
, (void *) &fbsurf
->drawable
);
212 fbsurf
->width
= vinfo
.xres
;
213 fbsurf
->height
= vinfo
.yres
;
215 if (resource_surface_set_size(fbsurf
->rsurf
,
216 fbsurf
->width
, fbsurf
->height
)) {
217 /* surface resized */
218 fbsurf
->sequence_number
++;
219 fbdpy
->event_handler
->invalid_surface(&fbdpy
->base
,
220 &fbsurf
->base
, fbsurf
->sequence_number
);
224 /* the drawable never changes */
225 ret
= resource_surface_present(fbsurf
->rsurf
,
226 natt
, (void *) &fbsurf
->drawable
);
233 fbdev_surface_wait(struct native_surface
*nsurf
)
239 fbdev_surface_destroy(struct native_surface
*nsurf
)
241 struct fbdev_surface
*fbsurf
= fbdev_surface(nsurf
);
243 resource_surface_destroy(fbsurf
->rsurf
);
247 static struct native_surface
*
248 fbdev_display_create_window_surface(struct native_display
*ndpy
,
249 EGLNativeWindowType win
,
250 const struct native_config
*nconf
)
252 struct fbdev_display
*fbdpy
= fbdev_display(ndpy
);
253 struct fbdev_surface
*fbsurf
;
254 struct fb_var_screeninfo vinfo
;
256 /* there is only one native window: NULL */
260 fbsurf
= CALLOC_STRUCT(fbdev_surface
);
264 fbsurf
->fbdpy
= fbdpy
;
266 /* get current vinfo */
267 if (fbdpy
->assume_fixed_vinfo
) {
268 vinfo
= fbdpy
->config_vinfo
;
271 memset(&vinfo
, 0, sizeof(vinfo
));
272 if (ioctl(fbdpy
->fd
, FBIOGET_VSCREENINFO
, &vinfo
)) {
278 fbsurf
->width
= vinfo
.xres
;
279 fbsurf
->height
= vinfo
.yres
;
281 if (!fbdev_surface_update_drawable(&fbsurf
->base
, &vinfo
)) {
286 fbsurf
->rsurf
= resource_surface_create(fbdpy
->base
.screen
,
288 PIPE_BIND_RENDER_TARGET
|
289 PIPE_BIND_DISPLAY_TARGET
);
290 if (!fbsurf
->rsurf
) {
295 resource_surface_set_size(fbsurf
->rsurf
, fbsurf
->width
, fbsurf
->height
);
297 fbsurf
->base
.destroy
= fbdev_surface_destroy
;
298 fbsurf
->base
.present
= fbdev_surface_present
;
299 fbsurf
->base
.validate
= fbdev_surface_validate
;
300 fbsurf
->base
.wait
= fbdev_surface_wait
;
302 return &fbsurf
->base
;
305 static struct native_surface
*
306 fbdev_display_create_scanout_surface(struct native_display
*ndpy
,
307 const struct native_config
*nconf
,
308 uint width
, uint height
)
310 return fbdev_display_create_window_surface(ndpy
,
311 (EGLNativeWindowType
) NULL
, nconf
);
315 fbdev_display_program(struct native_display
*ndpy
, int crtc_idx
,
316 struct native_surface
*nsurf
, uint x
, uint y
,
317 const struct native_connector
**nconns
, int num_nconns
,
318 const struct native_mode
*nmode
)
323 static const struct native_mode
**
324 fbdev_display_get_modes(struct native_display
*ndpy
,
325 const struct native_connector
*nconn
,
328 static struct native_mode mode
;
329 const struct native_mode
**modes
;
332 struct fbdev_display
*fbdpy
= fbdev_display(ndpy
);
333 mode
.desc
= "Current Mode";
334 mode
.width
= fbdpy
->config_vinfo
.xres
;
335 mode
.height
= fbdpy
->config_vinfo
.yres
;
336 mode
.refresh_rate
= 60 * 1000; /* dummy */
339 modes
= MALLOC(sizeof(*modes
));
349 static const struct native_connector
**
350 fbdev_display_get_connectors(struct native_display
*ndpy
, int *num_connectors
,
353 static struct native_connector connector
;
354 const struct native_connector
**connectors
;
356 connectors
= MALLOC(sizeof(*connectors
));
358 connectors
[0] = &connector
;
366 /* remove modeset support one day! */
367 static const struct native_display_modeset fbdev_display_modeset
= {
368 .get_connectors
= fbdev_display_get_connectors
,
369 .get_modes
= fbdev_display_get_modes
,
370 .create_scanout_surface
= fbdev_display_create_scanout_surface
,
371 .program
= fbdev_display_program
374 static const struct native_config
**
375 fbdev_display_get_configs(struct native_display
*ndpy
, int *num_configs
)
377 struct fbdev_display
*fbdpy
= fbdev_display(ndpy
);
378 const struct native_config
**configs
;
380 configs
= MALLOC(sizeof(*configs
));
382 configs
[0] = &fbdpy
->config
;
391 fbdev_display_get_param(struct native_display
*ndpy
,
392 enum native_param_type param
)
397 case NATIVE_PARAM_PRESERVE_BUFFER
:
400 case NATIVE_PARAM_USE_NATIVE_BUFFER
:
401 case NATIVE_PARAM_MAX_SWAP_INTERVAL
:
411 fbdev_display_destroy(struct native_display
*ndpy
)
413 struct fbdev_display
*fbdpy
= fbdev_display(ndpy
);
415 ndpy_uninit(&fbdpy
->base
);
421 fbdev_display_init_screen(struct native_display
*ndpy
)
423 struct fbdev_display
*fbdpy
= fbdev_display(ndpy
);
424 struct sw_winsys
*ws
;
426 ws
= fbdev_create_sw_winsys(fbdpy
->fd
);
430 fbdpy
->base
.screen
= fbdpy
->event_handler
->new_sw_screen(&fbdpy
->base
, ws
);
431 if (!fbdpy
->base
.screen
) {
437 if (!fbdpy
->base
.screen
->is_format_supported(fbdpy
->base
.screen
,
438 fbdpy
->config
.color_format
, PIPE_TEXTURE_2D
, 0,
439 PIPE_BIND_RENDER_TARGET
)) {
440 fbdpy
->base
.screen
->destroy(fbdpy
->base
.screen
);
441 fbdpy
->base
.screen
= NULL
;
449 fbdev_display_init_config(struct native_display
*ndpy
)
451 struct fbdev_display
*fbdpy
= fbdev_display(ndpy
);
452 struct native_config
*nconf
= &fbdpy
->config
;
454 if (ioctl(fbdpy
->fd
, FBIOGET_VSCREENINFO
, &fbdpy
->config_vinfo
))
457 nconf
->color_format
= vinfo_to_format(&fbdpy
->config_vinfo
);
458 if (nconf
->color_format
== PIPE_FORMAT_NONE
)
461 nconf
->buffer_mask
= (1 << NATIVE_ATTACHMENT_BACK_LEFT
);
463 nconf
->window_bit
= TRUE
;
468 static struct native_display
*
469 fbdev_display_create(int fd
, const struct native_event_handler
*event_handler
)
471 struct fbdev_display
*fbdpy
;
473 fbdpy
= CALLOC_STRUCT(fbdev_display
);
478 fbdpy
->event_handler
= event_handler
;
480 if (ioctl(fbdpy
->fd
, FBIOGET_FSCREENINFO
, &fbdpy
->finfo
))
483 if (fbdpy
->finfo
.visual
!= FB_VISUAL_TRUECOLOR
||
484 fbdpy
->finfo
.type
!= FB_TYPE_PACKED_PIXELS
)
487 if (!fbdev_display_init_config(&fbdpy
->base
))
490 fbdpy
->assume_fixed_vinfo
= TRUE
;
492 fbdpy
->base
.init_screen
= fbdev_display_init_screen
;
493 fbdpy
->base
.destroy
= fbdev_display_destroy
;
494 fbdpy
->base
.get_param
= fbdev_display_get_param
;
495 fbdpy
->base
.get_configs
= fbdev_display_get_configs
;
497 fbdpy
->base
.create_window_surface
= fbdev_display_create_window_surface
;
499 /* we'd like to remove modeset support one day */
500 fbdpy
->config
.scanout_bit
= TRUE
;
501 fbdpy
->base
.modeset
= &fbdev_display_modeset
;
510 static const struct native_event_handler
*fbdev_event_handler
;
512 static struct native_display
*
513 native_create_display(void *dpy
, boolean use_sw
)
515 struct native_display
*ndpy
;
518 /* well, this makes fd 0 being ignored */
520 fd
= open("/dev/fb0", O_RDWR
);
523 fd
= dup((int) pointer_to_intptr(dpy
));
528 ndpy
= fbdev_display_create(fd
, fbdev_event_handler
);
535 static const struct native_platform fbdev_platform
= {
537 native_create_display
540 const struct native_platform
*
541 native_get_fbdev_platform(const struct native_event_handler
*event_handler
)
543 fbdev_event_handler
= event_handler
;
544 return &fbdev_platform
;