native_fbdev.c revision 94bf657b2390a1cb72d748047e5c7014e4bc1752
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 boolean 141fbdev_surface_present(struct native_surface *nsurf, 142 enum native_attachment natt, 143 boolean preserve, 144 uint swap_interval) 145{ 146 boolean ret; 147 148 if (preserve || swap_interval) 149 return FALSE; 150 151 switch (natt) { 152 case NATIVE_ATTACHMENT_FRONT_LEFT: 153 ret = fbdev_surface_flush_frontbuffer(nsurf); 154 break; 155 case NATIVE_ATTACHMENT_BACK_LEFT: 156 ret = fbdev_surface_swap_buffers(nsurf); 157 break; 158 default: 159 ret = FALSE; 160 break; 161 } 162 163 return ret; 164} 165 166static void 167fbdev_surface_wait(struct native_surface *nsurf) 168{ 169 /* no-op */ 170} 171 172static void 173fbdev_surface_destroy(struct native_surface *nsurf) 174{ 175 struct fbdev_surface *fbsurf = fbdev_surface(nsurf); 176 177 resource_surface_destroy(fbsurf->rsurf); 178 FREE(fbsurf); 179} 180 181static struct native_surface * 182fbdev_display_create_scanout_surface(struct native_display *ndpy, 183 const struct native_config *nconf, 184 uint width, uint height) 185{ 186 struct fbdev_display *fbdpy = fbdev_display(ndpy); 187 struct fbdev_surface *fbsurf; 188 189 fbsurf = CALLOC_STRUCT(fbdev_surface); 190 if (!fbsurf) 191 return NULL; 192 193 fbsurf->fbdpy = fbdpy; 194 fbsurf->width = width; 195 fbsurf->height = height; 196 197 fbsurf->rsurf = resource_surface_create(fbdpy->base.screen, 198 nconf->color_format, 199 PIPE_BIND_RENDER_TARGET | 200 PIPE_BIND_DISPLAY_TARGET | 201 PIPE_BIND_SCANOUT); 202 if (!fbsurf->rsurf) { 203 FREE(fbsurf); 204 return NULL; 205 } 206 207 resource_surface_set_size(fbsurf->rsurf, fbsurf->width, fbsurf->height); 208 209 fbsurf->base.destroy = fbdev_surface_destroy; 210 fbsurf->base.swap_buffers = fbdev_surface_swap_buffers; 211 fbsurf->base.flush_frontbuffer = fbdev_surface_flush_frontbuffer; 212 fbsurf->base.present = fbdev_surface_present; 213 fbsurf->base.validate = fbdev_surface_validate; 214 fbsurf->base.wait = fbdev_surface_wait; 215 216 return &fbsurf->base; 217} 218 219static boolean 220fbdev_display_program(struct native_display *ndpy, int crtc_idx, 221 struct native_surface *nsurf, uint x, uint y, 222 const struct native_connector **nconns, int num_nconns, 223 const struct native_mode *nmode) 224{ 225 struct fbdev_display *fbdpy = fbdev_display(ndpy); 226 struct fbdev_surface *fbsurf = fbdev_surface(nsurf); 227 228 if (x || y) 229 return FALSE; 230 231 if (fbdpy->current_surface) { 232 if (fbdpy->current_surface == fbsurf) 233 return TRUE; 234 fbdpy->current_surface->is_current = FALSE; 235 } 236 237 if (fbsurf) 238 fbsurf->is_current = TRUE; 239 fbdpy->current_surface = fbsurf; 240 241 return TRUE; 242} 243 244static const struct native_mode ** 245fbdev_display_get_modes(struct native_display *ndpy, 246 const struct native_connector *nconn, 247 int *num_modes) 248{ 249 struct fbdev_display *fbdpy = fbdev_display(ndpy); 250 const struct native_mode **modes; 251 252 modes = MALLOC(sizeof(*modes)); 253 if (modes) { 254 modes[0] = &fbdpy->mode; 255 if (num_modes) 256 *num_modes = 1; 257 } 258 259 return modes; 260} 261 262static const struct native_connector ** 263fbdev_display_get_connectors(struct native_display *ndpy, int *num_connectors, 264 int *num_crtc) 265{ 266 struct fbdev_display *fbdpy = fbdev_display(ndpy); 267 const struct native_connector **connectors; 268 269 connectors = MALLOC(sizeof(*connectors)); 270 if (connectors) { 271 connectors[0] = &fbdpy->connector; 272 if (num_connectors) 273 *num_connectors = 1; 274 } 275 276 return connectors; 277} 278 279static struct native_display_modeset fbdev_display_modeset = { 280 .get_connectors = fbdev_display_get_connectors, 281 .get_modes = fbdev_display_get_modes, 282 .create_scanout_surface = fbdev_display_create_scanout_surface, 283 .program = fbdev_display_program 284}; 285 286static const struct native_config ** 287fbdev_display_get_configs(struct native_display *ndpy, int *num_configs) 288{ 289 struct fbdev_display *fbdpy = fbdev_display(ndpy); 290 const struct native_config **configs; 291 292 configs = MALLOC(sizeof(*configs)); 293 if (configs) { 294 configs[0] = &fbdpy->config; 295 if (num_configs) 296 *num_configs = 1; 297 } 298 299 return configs; 300} 301 302static int 303fbdev_display_get_param(struct native_display *ndpy, 304 enum native_param_type param) 305{ 306 int val; 307 308 switch (param) { 309 case NATIVE_PARAM_USE_NATIVE_BUFFER: 310 case NATIVE_PARAM_PRESERVE_BUFFER: 311 case NATIVE_PARAM_MAX_SWAP_INTERVAL: 312 default: 313 val = 0; 314 break; 315 } 316 317 return val; 318} 319 320static void 321fbdev_display_destroy(struct native_display *ndpy) 322{ 323 struct fbdev_display *fbdpy = fbdev_display(ndpy); 324 325 fbdpy->base.screen->destroy(fbdpy->base.screen); 326 close(fbdpy->fd); 327 FREE(fbdpy); 328} 329 330static boolean 331fbdev_display_init_modes(struct native_display *ndpy) 332{ 333 struct fbdev_display *fbdpy = fbdev_display(ndpy); 334 struct native_mode *nmode = &fbdpy->mode; 335 336 nmode->desc = "Current Mode"; 337 nmode->width = fbdpy->vinfo.xres; 338 nmode->height = fbdpy->vinfo.yres; 339 nmode->refresh_rate = 60 * 1000; /* dummy */ 340 341 return TRUE; 342} 343 344static boolean 345fbdev_display_init_connectors(struct native_display *ndpy) 346{ 347 return TRUE; 348} 349 350static enum pipe_format 351vinfo_to_format(const struct fb_var_screeninfo *vinfo) 352{ 353 enum pipe_format format = PIPE_FORMAT_NONE; 354 355 switch (vinfo->bits_per_pixel) { 356 case 32: 357 if (vinfo->red.length == 8 && 358 vinfo->green.length == 8 && 359 vinfo->blue.length == 8) { 360 format = (vinfo->transp.length == 8) ? 361 PIPE_FORMAT_B8G8R8A8_UNORM : PIPE_FORMAT_B8G8R8X8_UNORM; 362 } 363 break; 364 case 16: 365 if (vinfo->red.length == 5 && 366 vinfo->green.length == 6 && 367 vinfo->blue.length == 5 && 368 vinfo->transp.length == 0) 369 format = PIPE_FORMAT_B5G6R5_UNORM; 370 break; 371 default: 372 break; 373 } 374 375 return format; 376} 377 378static boolean 379fbdev_display_init_configs(struct native_display *ndpy) 380{ 381 struct fbdev_display *fbdpy = fbdev_display(ndpy); 382 struct native_config *nconf = &fbdpy->config; 383 384 nconf->color_format = vinfo_to_format(&fbdpy->vinfo); 385 if (nconf->color_format == PIPE_FORMAT_NONE) 386 return FALSE; 387 388 nconf->buffer_mask = 389 (1 << NATIVE_ATTACHMENT_FRONT_LEFT) | 390 (1 << NATIVE_ATTACHMENT_BACK_LEFT); 391 392 nconf->scanout_bit = TRUE; 393 394 return TRUE; 395} 396 397static boolean 398fbdev_display_init(struct native_display *ndpy) 399{ 400 struct fbdev_display *fbdpy = fbdev_display(ndpy); 401 struct sw_winsys *ws; 402 403 if (ioctl(fbdpy->fd, FBIOGET_FSCREENINFO, &fbdpy->finfo)) 404 return FALSE; 405 406 if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &fbdpy->vinfo)) 407 return FALSE; 408 409 if (fbdpy->finfo.visual != FB_VISUAL_TRUECOLOR || 410 fbdpy->finfo.type != FB_TYPE_PACKED_PIXELS) 411 return FALSE; 412 413 if (!fbdev_display_init_configs(&fbdpy->base) || 414 !fbdev_display_init_connectors(&fbdpy->base) || 415 !fbdev_display_init_modes(&fbdpy->base)) 416 return FALSE; 417 418 ws = fbdev_create_sw_winsys(fbdpy->fd, fbdpy->config.color_format); 419 if (ws) { 420 fbdpy->base.screen = 421 fbdpy->event_handler->new_sw_screen(&fbdpy->base, ws); 422 } 423 424 if (fbdpy->base.screen) { 425 if (!fbdpy->base.screen->is_format_supported(fbdpy->base.screen, 426 fbdpy->config.color_format, PIPE_TEXTURE_2D, 0, 427 PIPE_BIND_RENDER_TARGET, 0)) { 428 fbdpy->base.screen->destroy(fbdpy->base.screen); 429 fbdpy->base.screen = NULL; 430 } 431 } 432 433 return (fbdpy->base.screen != NULL); 434} 435 436static struct native_display * 437fbdev_display_create(int fd, struct native_event_handler *event_handler, 438 void *user_data) 439{ 440 struct fbdev_display *fbdpy; 441 442 fbdpy = CALLOC_STRUCT(fbdev_display); 443 if (!fbdpy) 444 return NULL; 445 446 fbdpy->fd = fd; 447 fbdpy->event_handler = event_handler; 448 fbdpy->base.user_data = user_data; 449 450 if (!fbdev_display_init(&fbdpy->base)) { 451 FREE(fbdpy); 452 return NULL; 453 } 454 455 fbdpy->base.destroy = fbdev_display_destroy; 456 fbdpy->base.get_param = fbdev_display_get_param; 457 fbdpy->base.get_configs = fbdev_display_get_configs; 458 459 fbdpy->base.modeset = &fbdev_display_modeset; 460 461 return &fbdpy->base; 462} 463 464static struct native_display * 465native_create_display(void *dpy, struct native_event_handler *event_handler, 466 void *user_data) 467{ 468 struct native_display *ndpy; 469 int fd; 470 471 /* well, this makes fd 0 being ignored */ 472 if (!dpy) { 473 fd = open("/dev/fb0", O_RDWR); 474 } 475 else { 476 fd = dup((int) pointer_to_intptr(dpy)); 477 } 478 if (fd < 0) 479 return NULL; 480 481 ndpy = fbdev_display_create(fd, event_handler, user_data); 482 if (!ndpy) 483 close(fd); 484 485 return ndpy; 486} 487 488static const struct native_platform fbdev_platform = { 489 "FBDEV", /* name */ 490 native_create_display 491}; 492 493const struct native_platform * 494native_get_fbdev_platform(void) 495{ 496 return &fbdev_platform; 497} 498