native_fbdev.c revision d5ab243d5a5bacbd2ba615d40f13c8ab37364745
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.9 4 * 5 * Copyright (C) 2010 LunarG Inc. 6 * 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: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 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. 24 * 25 * Authors: 26 * Chia-I Wu <olv@lunarg.com> 27 */ 28 29#include <sys/ioctl.h> 30#include <sys/types.h> 31#include <sys/stat.h> 32#include <fcntl.h> 33#include <linux/fb.h> 34 35#include "pipe/p_screen.h" 36#include "util/u_memory.h" 37#include "util/u_inlines.h" 38#include "util/u_pointer.h" 39 40#include "common/native.h" 41#include "common/native_helper.h" 42#include "fbdev/fbdev_sw_winsys.h" 43 44struct fbdev_display { 45 struct native_display base; 46 47 int fd; 48 struct native_event_handler *event_handler; 49 50 struct fb_fix_screeninfo finfo; 51 struct fb_var_screeninfo vinfo; 52 53 struct native_config config; 54 struct native_connector connector; 55 struct native_mode mode; 56 57 struct fbdev_surface *current_surface; 58}; 59 60struct fbdev_surface { 61 struct native_surface base; 62 63 struct fbdev_display *fbdpy; 64 struct resource_surface *rsurf; 65 int width, height; 66 67 unsigned int sequence_number; 68 69 boolean is_current; 70}; 71 72static INLINE struct fbdev_display * 73fbdev_display(const struct native_display *ndpy) 74{ 75 return (struct fbdev_display *) ndpy; 76} 77 78static INLINE struct fbdev_surface * 79fbdev_surface(const struct native_surface *nsurf) 80{ 81 return (struct fbdev_surface *) nsurf; 82} 83 84static boolean 85fbdev_surface_validate(struct native_surface *nsurf, uint attachment_mask, 86 unsigned int *seq_num, struct pipe_resource **textures, 87 int *width, int *height) 88{ 89 struct fbdev_surface *fbsurf = fbdev_surface(nsurf); 90 91 if (!resource_surface_add_resources(fbsurf->rsurf, attachment_mask)) 92 return FALSE; 93 if (textures) 94 resource_surface_get_resources(fbsurf->rsurf, textures, attachment_mask); 95 96 if (seq_num) 97 *seq_num = fbsurf->sequence_number; 98 if (width) 99 *width = fbsurf->width; 100 if (height) 101 *height = fbsurf->height; 102 103 return TRUE; 104} 105 106static boolean 107fbdev_surface_flush_frontbuffer(struct native_surface *nsurf) 108{ 109 struct fbdev_surface *fbsurf = fbdev_surface(nsurf); 110 111 if (!fbsurf->is_current) 112 return TRUE; 113 114 return resource_surface_present(fbsurf->rsurf, 115 NATIVE_ATTACHMENT_FRONT_LEFT, NULL); 116} 117 118static boolean 119fbdev_surface_swap_buffers(struct native_surface *nsurf) 120{ 121 struct fbdev_surface *fbsurf = fbdev_surface(nsurf); 122 struct fbdev_display *fbdpy = fbsurf->fbdpy; 123 boolean ret = TRUE; 124 125 if (fbsurf->is_current) { 126 ret = resource_surface_present(fbsurf->rsurf, 127 NATIVE_ATTACHMENT_BACK_LEFT, NULL); 128 } 129 130 resource_surface_swap_buffers(fbsurf->rsurf, 131 NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, TRUE); 132 /* the front/back textures are swapped */ 133 fbsurf->sequence_number++; 134 fbdpy->event_handler->invalid_surface(&fbdpy->base, 135 &fbsurf->base, fbsurf->sequence_number); 136 137 return ret; 138} 139 140static void 141fbdev_surface_wait(struct native_surface *nsurf) 142{ 143 /* no-op */ 144} 145 146static void 147fbdev_surface_destroy(struct native_surface *nsurf) 148{ 149 struct fbdev_surface *fbsurf = fbdev_surface(nsurf); 150 151 resource_surface_destroy(fbsurf->rsurf); 152 FREE(fbsurf); 153} 154 155static struct native_surface * 156fbdev_display_create_scanout_surface(struct native_display *ndpy, 157 const struct native_config *nconf, 158 uint width, uint height) 159{ 160 struct fbdev_display *fbdpy = fbdev_display(ndpy); 161 struct fbdev_surface *fbsurf; 162 163 fbsurf = CALLOC_STRUCT(fbdev_surface); 164 if (!fbsurf) 165 return NULL; 166 167 fbsurf->fbdpy = fbdpy; 168 fbsurf->width = width; 169 fbsurf->height = height; 170 171 fbsurf->rsurf = resource_surface_create(fbdpy->base.screen, 172 nconf->color_format, 173 PIPE_BIND_RENDER_TARGET | 174 PIPE_BIND_DISPLAY_TARGET | 175 PIPE_BIND_SCANOUT); 176 if (!fbsurf->rsurf) { 177 FREE(fbsurf); 178 return NULL; 179 } 180 181 resource_surface_set_size(fbsurf->rsurf, fbsurf->width, fbsurf->height); 182 183 fbsurf->base.destroy = fbdev_surface_destroy; 184 fbsurf->base.swap_buffers = fbdev_surface_swap_buffers; 185 fbsurf->base.flush_frontbuffer = fbdev_surface_flush_frontbuffer; 186 fbsurf->base.validate = fbdev_surface_validate; 187 fbsurf->base.wait = fbdev_surface_wait; 188 189 return &fbsurf->base; 190} 191 192static boolean 193fbdev_display_program(struct native_display *ndpy, int crtc_idx, 194 struct native_surface *nsurf, uint x, uint y, 195 const struct native_connector **nconns, int num_nconns, 196 const struct native_mode *nmode) 197{ 198 struct fbdev_display *fbdpy = fbdev_display(ndpy); 199 struct fbdev_surface *fbsurf = fbdev_surface(nsurf); 200 201 if (x || y) 202 return FALSE; 203 204 if (fbdpy->current_surface) { 205 if (fbdpy->current_surface == fbsurf) 206 return TRUE; 207 fbdpy->current_surface->is_current = FALSE; 208 } 209 210 if (fbsurf) 211 fbsurf->is_current = TRUE; 212 fbdpy->current_surface = fbsurf; 213 214 return TRUE; 215} 216 217static const struct native_mode ** 218fbdev_display_get_modes(struct native_display *ndpy, 219 const struct native_connector *nconn, 220 int *num_modes) 221{ 222 struct fbdev_display *fbdpy = fbdev_display(ndpy); 223 const struct native_mode **modes; 224 225 modes = MALLOC(sizeof(*modes)); 226 if (modes) { 227 modes[0] = &fbdpy->mode; 228 if (num_modes) 229 *num_modes = 1; 230 } 231 232 return modes; 233} 234 235static const struct native_connector ** 236fbdev_display_get_connectors(struct native_display *ndpy, int *num_connectors, 237 int *num_crtc) 238{ 239 struct fbdev_display *fbdpy = fbdev_display(ndpy); 240 const struct native_connector **connectors; 241 242 connectors = MALLOC(sizeof(*connectors)); 243 if (connectors) { 244 connectors[0] = &fbdpy->connector; 245 if (num_connectors) 246 *num_connectors = 1; 247 } 248 249 return connectors; 250} 251 252static struct native_display_modeset fbdev_display_modeset = { 253 .get_connectors = fbdev_display_get_connectors, 254 .get_modes = fbdev_display_get_modes, 255 .create_scanout_surface = fbdev_display_create_scanout_surface, 256 .program = fbdev_display_program 257}; 258 259static const struct native_config ** 260fbdev_display_get_configs(struct native_display *ndpy, int *num_configs) 261{ 262 struct fbdev_display *fbdpy = fbdev_display(ndpy); 263 const struct native_config **configs; 264 265 configs = MALLOC(sizeof(*configs)); 266 if (configs) { 267 configs[0] = &fbdpy->config; 268 if (num_configs) 269 *num_configs = 1; 270 } 271 272 return configs; 273} 274 275static int 276fbdev_display_get_param(struct native_display *ndpy, 277 enum native_param_type param) 278{ 279 int val; 280 281 switch (param) { 282 default: 283 val = 0; 284 break; 285 } 286 287 return val; 288} 289 290static void 291fbdev_display_destroy(struct native_display *ndpy) 292{ 293 struct fbdev_display *fbdpy = fbdev_display(ndpy); 294 295 fbdpy->base.screen->destroy(fbdpy->base.screen); 296 close(fbdpy->fd); 297 FREE(fbdpy); 298} 299 300static boolean 301fbdev_display_init_modes(struct native_display *ndpy) 302{ 303 struct fbdev_display *fbdpy = fbdev_display(ndpy); 304 struct native_mode *nmode = &fbdpy->mode; 305 306 nmode->desc = "Current Mode"; 307 nmode->width = fbdpy->vinfo.xres; 308 nmode->height = fbdpy->vinfo.yres; 309 nmode->refresh_rate = 60 * 1000; /* dummy */ 310 311 return TRUE; 312} 313 314static boolean 315fbdev_display_init_connectors(struct native_display *ndpy) 316{ 317 return TRUE; 318} 319 320static enum pipe_format 321vinfo_to_format(const struct fb_var_screeninfo *vinfo) 322{ 323 enum pipe_format format = PIPE_FORMAT_NONE; 324 325 switch (vinfo->bits_per_pixel) { 326 case 32: 327 if (vinfo->red.length == 8 && 328 vinfo->green.length == 8 && 329 vinfo->blue.length == 8) { 330 format = (vinfo->transp.length == 8) ? 331 PIPE_FORMAT_B8G8R8A8_UNORM : PIPE_FORMAT_B8G8R8X8_UNORM; 332 } 333 break; 334 case 16: 335 if (vinfo->red.length == 5 && 336 vinfo->green.length == 6 && 337 vinfo->blue.length == 5 && 338 vinfo->transp.length == 0) 339 format = PIPE_FORMAT_B5G6R5_UNORM; 340 break; 341 default: 342 break; 343 } 344 345 return format; 346} 347 348static boolean 349fbdev_display_init_configs(struct native_display *ndpy) 350{ 351 struct fbdev_display *fbdpy = fbdev_display(ndpy); 352 struct native_config *nconf = &fbdpy->config; 353 354 nconf->color_format = vinfo_to_format(&fbdpy->vinfo); 355 if (nconf->color_format == PIPE_FORMAT_NONE) 356 return FALSE; 357 358 nconf->buffer_mask = 359 (1 << NATIVE_ATTACHMENT_FRONT_LEFT) | 360 (1 << NATIVE_ATTACHMENT_BACK_LEFT); 361 362 nconf->scanout_bit = TRUE; 363 364 return TRUE; 365} 366 367static boolean 368fbdev_display_init(struct native_display *ndpy) 369{ 370 struct fbdev_display *fbdpy = fbdev_display(ndpy); 371 struct sw_winsys *ws; 372 373 if (ioctl(fbdpy->fd, FBIOGET_FSCREENINFO, &fbdpy->finfo)) 374 return FALSE; 375 376 if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &fbdpy->vinfo)) 377 return FALSE; 378 379 if (fbdpy->finfo.visual != FB_VISUAL_TRUECOLOR || 380 fbdpy->finfo.type != FB_TYPE_PACKED_PIXELS) 381 return FALSE; 382 383 if (!fbdev_display_init_configs(&fbdpy->base) || 384 !fbdev_display_init_connectors(&fbdpy->base) || 385 !fbdev_display_init_modes(&fbdpy->base)) 386 return FALSE; 387 388 ws = fbdev_create_sw_winsys(fbdpy->fd, fbdpy->config.color_format); 389 if (ws) { 390 fbdpy->base.screen = 391 fbdpy->event_handler->new_sw_screen(&fbdpy->base, ws); 392 } 393 394 if (fbdpy->base.screen) { 395 if (!fbdpy->base.screen->is_format_supported(fbdpy->base.screen, 396 fbdpy->config.color_format, PIPE_TEXTURE_2D, 0, 397 PIPE_BIND_RENDER_TARGET, 0)) { 398 fbdpy->base.screen->destroy(fbdpy->base.screen); 399 fbdpy->base.screen = NULL; 400 } 401 } 402 403 return (fbdpy->base.screen != NULL); 404} 405 406static struct native_display * 407fbdev_display_create(int fd, struct native_event_handler *event_handler, 408 void *user_data) 409{ 410 struct fbdev_display *fbdpy; 411 412 fbdpy = CALLOC_STRUCT(fbdev_display); 413 if (!fbdpy) 414 return NULL; 415 416 fbdpy->fd = fd; 417 fbdpy->event_handler = event_handler; 418 fbdpy->base.user_data = user_data; 419 420 if (!fbdev_display_init(&fbdpy->base)) { 421 FREE(fbdpy); 422 return NULL; 423 } 424 425 fbdpy->base.destroy = fbdev_display_destroy; 426 fbdpy->base.get_param = fbdev_display_get_param; 427 fbdpy->base.get_configs = fbdev_display_get_configs; 428 429 fbdpy->base.modeset = &fbdev_display_modeset; 430 431 return &fbdpy->base; 432} 433 434static struct native_display * 435native_create_display(void *dpy, struct native_event_handler *event_handler, 436 void *user_data) 437{ 438 struct native_display *ndpy; 439 int fd; 440 441 /* well, this makes fd 0 being ignored */ 442 if (!dpy) { 443 fd = open("/dev/fb0", O_RDWR); 444 } 445 else { 446 fd = dup((int) pointer_to_intptr(dpy)); 447 } 448 if (fd < 0) 449 return NULL; 450 451 ndpy = fbdev_display_create(fd, event_handler, user_data); 452 if (!ndpy) 453 close(fd); 454 455 return ndpy; 456} 457 458static const struct native_platform fbdev_platform = { 459 "FBDEV", /* name */ 460 NULL, /* create_probe */ 461 NULL, /* get_probe_result */ 462 native_create_display 463}; 464 465const struct native_platform * 466native_get_fbdev_platform(void) 467{ 468 return &fbdev_platform; 469} 470