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;