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