Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 2010 LunarG Inc.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included
  14.  * in all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22.  * DEALINGS IN THE SOFTWARE.
  23.  *
  24.  * Authors:
  25.  *    Chia-I Wu <olv@lunarg.com>
  26.  */
  27.  
  28. /**
  29.  * Considering fbdev as an in-kernel window system,
  30.  *
  31.  *  - opening a device opens a connection
  32.  *  - there is only one window: the framebuffer
  33.  *  - fb_var_screeninfo decides window position, size, and even color format
  34.  *  - there is no pixmap
  35.  *
  36.  * Now EGL is built on top of this window system.  So we should have
  37.  *
  38.  *  - the fd as the handle of the native display
  39.  *  - reject all but one native window: NULL
  40.  *  - no pixmap support
  41.  */
  42.  
  43. #include <errno.h>
  44. #include <sys/ioctl.h>
  45. #include <sys/types.h>
  46. #include <sys/stat.h>
  47. #include <fcntl.h>
  48. #include <linux/fb.h>
  49.  
  50. #include "pipe/p_screen.h"
  51. #include "util/u_memory.h"
  52. #include "util/u_inlines.h"
  53. #include "util/u_pointer.h"
  54.  
  55. #include "common/native.h"
  56. #include "common/native_helper.h"
  57. #include "fbdev/fbdev_sw_winsys.h"
  58.  
  59. struct fbdev_display {
  60.    struct native_display base;
  61.  
  62.    int fd;
  63.    const struct native_event_handler *event_handler;
  64.  
  65.    struct fb_fix_screeninfo finfo;
  66.    struct fb_var_screeninfo config_vinfo;
  67.    struct native_config config;
  68.  
  69.    boolean assume_fixed_vinfo;
  70. };
  71.  
  72. struct fbdev_surface {
  73.    struct native_surface base;
  74.  
  75.    struct fbdev_display *fbdpy;
  76.    struct resource_surface *rsurf;
  77.    int width, height;
  78.  
  79.    unsigned int sequence_number;
  80.  
  81.    struct fbdev_sw_drawable drawable;
  82. };
  83.  
  84. static INLINE struct fbdev_display *
  85. fbdev_display(const struct native_display *ndpy)
  86. {
  87.    return (struct fbdev_display *) ndpy;
  88. }
  89.  
  90. static INLINE struct fbdev_surface *
  91. fbdev_surface(const struct native_surface *nsurf)
  92. {
  93.    return (struct fbdev_surface *) nsurf;
  94. }
  95.  
  96. static boolean
  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)
  100. {
  101.    struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
  102.  
  103.    if (!resource_surface_add_resources(fbsurf->rsurf, attachment_mask))
  104.       return FALSE;
  105.    if (textures)
  106.       resource_surface_get_resources(fbsurf->rsurf, textures, attachment_mask);
  107.  
  108.    if (seq_num)
  109.       *seq_num = fbsurf->sequence_number;
  110.    if (width)
  111.       *width = fbsurf->width;
  112.    if (height)
  113.       *height = fbsurf->height;
  114.  
  115.    return TRUE;
  116. }
  117.  
  118. static enum pipe_format
  119. vinfo_to_format(const struct fb_var_screeninfo *vinfo)
  120. {
  121.    enum pipe_format format = PIPE_FORMAT_NONE;
  122.  
  123.    /* should also check channel offsets... */
  124.    switch (vinfo->bits_per_pixel) {
  125.    case 32:
  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;
  131.       }
  132.       break;
  133.    case 16:
  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;
  139.       break;
  140.    default:
  141.       break;
  142.    }
  143.  
  144.    return format;
  145. }
  146.  
  147. static boolean
  148. fbdev_surface_update_drawable(struct native_surface *nsurf,
  149.                               const struct fb_var_screeninfo *vinfo)
  150. {
  151.    struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
  152.    unsigned x, y, width, height;
  153.  
  154.    x = vinfo->xoffset;
  155.    y = vinfo->yoffset;
  156.    width = MIN2(vinfo->xres, fbsurf->width);
  157.    height = MIN2(vinfo->yres, fbsurf->height);
  158.  
  159.    /* sanitize the values */
  160.    if (x + width > vinfo->xres_virtual) {
  161.       if (x > vinfo->xres_virtual)
  162.          width = 0;
  163.       else
  164.          width = vinfo->xres_virtual - x;
  165.    }
  166.    if (y + height > vinfo->yres_virtual) {
  167.       if (y > vinfo->yres_virtual)
  168.          height = 0;
  169.       else
  170.          height = vinfo->yres_virtual - y;
  171.    }
  172.  
  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;
  178.  
  179.    return (fbsurf->drawable.format != PIPE_FORMAT_NONE &&
  180.            fbsurf->drawable.width &&
  181.            fbsurf->drawable.height);
  182. }
  183.  
  184. static boolean
  185. fbdev_surface_present(struct native_surface *nsurf,
  186.                       const struct native_present_control *ctrl)
  187. {
  188.    struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
  189.    struct fbdev_display *fbdpy = fbsurf->fbdpy;
  190.    boolean ret = FALSE;
  191.  
  192.    if (ctrl->swap_interval)
  193.       return FALSE;
  194.    if (ctrl->natt != NATIVE_ATTACHMENT_BACK_LEFT)
  195.       return FALSE;
  196.  
  197.    if (!fbdpy->assume_fixed_vinfo) {
  198.       struct fb_var_screeninfo vinfo;
  199.  
  200.       memset(&vinfo, 0, sizeof(vinfo));
  201.       if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &vinfo))
  202.          return FALSE;
  203.  
  204.       /* present the surface */
  205.       if (fbdev_surface_update_drawable(&fbsurf->base, &vinfo)) {
  206.          ret = resource_surface_present(fbsurf->rsurf,
  207.                ctrl->natt, (void *) &fbsurf->drawable);
  208.       }
  209.  
  210.       fbsurf->width = vinfo.xres;
  211.       fbsurf->height = vinfo.yres;
  212.  
  213.       if (resource_surface_set_size(fbsurf->rsurf,
  214.                fbsurf->width, fbsurf->height)) {
  215.          /* surface resized */
  216.          fbsurf->sequence_number++;
  217.          fbdpy->event_handler->invalid_surface(&fbdpy->base,
  218.                &fbsurf->base, fbsurf->sequence_number);
  219.       }
  220.    }
  221.    else {
  222.       /* the drawable never changes */
  223.       ret = resource_surface_present(fbsurf->rsurf,
  224.             ctrl->natt, (void *) &fbsurf->drawable);
  225.    }
  226.  
  227.    return ret;
  228. }
  229.  
  230. static void
  231. fbdev_surface_wait(struct native_surface *nsurf)
  232. {
  233.    /* no-op */
  234. }
  235.  
  236. static void
  237. fbdev_surface_destroy(struct native_surface *nsurf)
  238. {
  239.    struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
  240.  
  241.    resource_surface_destroy(fbsurf->rsurf);
  242.    FREE(fbsurf);
  243. }
  244.  
  245. static struct native_surface *
  246. fbdev_display_create_window_surface(struct native_display *ndpy,
  247.                                     EGLNativeWindowType win,
  248.                                     const struct native_config *nconf)
  249. {
  250.    struct fbdev_display *fbdpy = fbdev_display(ndpy);
  251.    struct fbdev_surface *fbsurf;
  252.    struct fb_var_screeninfo vinfo;
  253.  
  254.    /* there is only one native window: NULL */
  255.    if (win)
  256.       return NULL;
  257.  
  258.    fbsurf = CALLOC_STRUCT(fbdev_surface);
  259.    if (!fbsurf)
  260.       return NULL;
  261.  
  262.    fbsurf->fbdpy = fbdpy;
  263.  
  264.    /* get current vinfo */
  265.    if (fbdpy->assume_fixed_vinfo) {
  266.       vinfo = fbdpy->config_vinfo;
  267.    }
  268.    else {
  269.       memset(&vinfo, 0, sizeof(vinfo));
  270.       if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &vinfo)) {
  271.          FREE(fbsurf);
  272.          return NULL;
  273.       }
  274.    }
  275.  
  276.    fbsurf->width = vinfo.xres;
  277.    fbsurf->height = vinfo.yres;
  278.  
  279.    if (!fbdev_surface_update_drawable(&fbsurf->base, &vinfo)) {
  280.       FREE(fbsurf);
  281.       return NULL;
  282.    }
  283.  
  284.    fbsurf->rsurf = resource_surface_create(fbdpy->base.screen,
  285.          nconf->color_format,
  286.          PIPE_BIND_RENDER_TARGET |
  287.          PIPE_BIND_DISPLAY_TARGET);
  288.    if (!fbsurf->rsurf) {
  289.       FREE(fbsurf);
  290.       return NULL;
  291.    }
  292.  
  293.    resource_surface_set_size(fbsurf->rsurf, fbsurf->width, fbsurf->height);
  294.  
  295.    fbsurf->base.destroy = fbdev_surface_destroy;
  296.    fbsurf->base.present = fbdev_surface_present;
  297.    fbsurf->base.validate = fbdev_surface_validate;
  298.    fbsurf->base.wait = fbdev_surface_wait;
  299.  
  300.    return &fbsurf->base;
  301. }
  302.  
  303. static struct native_surface *
  304. fbdev_display_create_scanout_surface(struct native_display *ndpy,
  305.                                      const struct native_config *nconf,
  306.                                      uint width, uint height)
  307. {
  308.    return fbdev_display_create_window_surface(ndpy,
  309.          (EGLNativeWindowType) NULL, nconf);
  310. }
  311.  
  312. static boolean
  313. fbdev_display_program(struct native_display *ndpy, int crtc_idx,
  314.                       struct native_surface *nsurf, uint x, uint y,
  315.                       const struct native_connector **nconns, int num_nconns,
  316.                       const struct native_mode *nmode)
  317. {
  318.    return TRUE;
  319. }
  320.  
  321. static const struct native_mode **
  322. fbdev_display_get_modes(struct native_display *ndpy,
  323.                         const struct native_connector *nconn,
  324.                         int *num_modes)
  325. {
  326.    static struct native_mode mode;
  327.    const struct native_mode **modes;
  328.  
  329.    if (!mode.desc) {
  330.       struct fbdev_display *fbdpy = fbdev_display(ndpy);
  331.       mode.desc = "Current Mode";
  332.       mode.width = fbdpy->config_vinfo.xres;
  333.       mode.height = fbdpy->config_vinfo.yres;
  334.       mode.refresh_rate = 60 * 1000; /* dummy */
  335.    }
  336.  
  337.    modes = MALLOC(sizeof(*modes));
  338.    if (modes) {
  339.       modes[0] = &mode;
  340.       if (num_modes)
  341.          *num_modes = 1;
  342.    }
  343.  
  344.    return modes;
  345. }
  346.  
  347. static const struct native_connector **
  348. fbdev_display_get_connectors(struct native_display *ndpy, int *num_connectors,
  349.                            int *num_crtc)
  350. {
  351.    static struct native_connector connector;
  352.    const struct native_connector **connectors;
  353.  
  354.    connectors = MALLOC(sizeof(*connectors));
  355.    if (connectors) {
  356.       connectors[0] = &connector;
  357.       if (num_connectors)
  358.          *num_connectors = 1;
  359.    }
  360.  
  361.    return connectors;
  362. }
  363.  
  364. /* remove modeset support one day! */
  365. static const struct native_display_modeset fbdev_display_modeset = {
  366.    .get_connectors = fbdev_display_get_connectors,
  367.    .get_modes = fbdev_display_get_modes,
  368.    .create_scanout_surface = fbdev_display_create_scanout_surface,
  369.    .program = fbdev_display_program
  370. };
  371.  
  372. static const struct native_config **
  373. fbdev_display_get_configs(struct native_display *ndpy, int *num_configs)
  374. {
  375.    struct fbdev_display *fbdpy = fbdev_display(ndpy);
  376.    const struct native_config **configs;
  377.  
  378.    configs = MALLOC(sizeof(*configs));
  379.    if (configs) {
  380.       configs[0] = &fbdpy->config;
  381.       if (num_configs)
  382.          *num_configs = 1;
  383.    }
  384.  
  385.    return configs;
  386. }
  387.  
  388. static int
  389. fbdev_display_get_param(struct native_display *ndpy,
  390.                       enum native_param_type param)
  391. {
  392.    int val;
  393.  
  394.    switch (param) {
  395.    case NATIVE_PARAM_PRESERVE_BUFFER:
  396.       val = 1;
  397.       break;
  398.    case NATIVE_PARAM_USE_NATIVE_BUFFER:
  399.    case NATIVE_PARAM_MAX_SWAP_INTERVAL:
  400.    default:
  401.       val = 0;
  402.       break;
  403.    }
  404.  
  405.    return val;
  406. }
  407.  
  408. static void
  409. fbdev_display_destroy(struct native_display *ndpy)
  410. {
  411.    struct fbdev_display *fbdpy = fbdev_display(ndpy);
  412.  
  413.    ndpy_uninit(&fbdpy->base);
  414.    close(fbdpy->fd);
  415.    FREE(fbdpy);
  416. }
  417.  
  418. static boolean
  419. fbdev_display_init_screen(struct native_display *ndpy)
  420. {
  421.    struct fbdev_display *fbdpy = fbdev_display(ndpy);
  422.    struct sw_winsys *ws;
  423.  
  424.    ws = fbdev_create_sw_winsys(fbdpy->fd);
  425.    if (!ws)
  426.       return FALSE;
  427.  
  428.    fbdpy->base.screen = fbdpy->event_handler->new_sw_screen(&fbdpy->base, ws);
  429.    if (!fbdpy->base.screen) {
  430.       if (ws->destroy)
  431.          ws->destroy(ws);
  432.       return FALSE;
  433.    }
  434.  
  435.    if (!fbdpy->base.screen->is_format_supported(fbdpy->base.screen,
  436.             fbdpy->config.color_format, PIPE_TEXTURE_2D, 0,
  437.             PIPE_BIND_RENDER_TARGET)) {
  438.       fbdpy->base.screen->destroy(fbdpy->base.screen);
  439.       fbdpy->base.screen = NULL;
  440.       return FALSE;
  441.    }
  442.  
  443.    return TRUE;
  444. }
  445.  
  446. static boolean
  447. fbdev_display_init_config(struct native_display *ndpy)
  448. {
  449.    struct fbdev_display *fbdpy = fbdev_display(ndpy);
  450.    struct native_config *nconf = &fbdpy->config;
  451.  
  452.    if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &fbdpy->config_vinfo))
  453.       return FALSE;
  454.  
  455.    nconf->color_format = vinfo_to_format(&fbdpy->config_vinfo);
  456.    if (nconf->color_format == PIPE_FORMAT_NONE)
  457.       return FALSE;
  458.  
  459.    nconf->buffer_mask = (1 << NATIVE_ATTACHMENT_BACK_LEFT);
  460.  
  461.    nconf->window_bit = TRUE;
  462.  
  463.    return TRUE;
  464. }
  465.  
  466. static struct native_display *
  467. fbdev_display_create(int fd, const struct native_event_handler *event_handler)
  468. {
  469.    struct fbdev_display *fbdpy;
  470.  
  471.    fbdpy = CALLOC_STRUCT(fbdev_display);
  472.    if (!fbdpy)
  473.       return NULL;
  474.  
  475.    fbdpy->fd = fd;
  476.    fbdpy->event_handler = event_handler;
  477.  
  478.    if (ioctl(fbdpy->fd, FBIOGET_FSCREENINFO, &fbdpy->finfo))
  479.       goto fail;
  480.  
  481.    if (fbdpy->finfo.visual != FB_VISUAL_TRUECOLOR ||
  482.        fbdpy->finfo.type != FB_TYPE_PACKED_PIXELS)
  483.       goto fail;
  484.  
  485.    if (!fbdev_display_init_config(&fbdpy->base))
  486.       goto fail;
  487.  
  488.    fbdpy->assume_fixed_vinfo = TRUE;
  489.  
  490.    fbdpy->base.init_screen = fbdev_display_init_screen;
  491.    fbdpy->base.destroy = fbdev_display_destroy;
  492.    fbdpy->base.get_param = fbdev_display_get_param;
  493.    fbdpy->base.get_configs = fbdev_display_get_configs;
  494.  
  495.    fbdpy->base.create_window_surface = fbdev_display_create_window_surface;
  496.  
  497.    /* we'd like to remove modeset support one day */
  498.    fbdpy->config.scanout_bit = TRUE;
  499.    fbdpy->base.modeset = &fbdev_display_modeset;
  500.  
  501.    return &fbdpy->base;
  502.  
  503. fail:
  504.    FREE(fbdpy);
  505.    return NULL;
  506. }
  507.  
  508. static const struct native_event_handler *fbdev_event_handler;
  509.  
  510. static struct native_display *
  511. native_create_display(void *dpy, boolean use_sw)
  512. {
  513.    struct native_display *ndpy;
  514.    int fd;
  515.  
  516.    /* well, this makes fd 0 being ignored */
  517.    if (!dpy) {
  518.       const char *device_name="/dev/fb0";
  519. #ifdef O_CLOEXEC
  520.       fd = open(device_name, O_RDWR | O_CLOEXEC);
  521.       if (fd == -1 && errno == EINVAL)
  522. #endif
  523.       {
  524.          fd = open(device_name, O_RDWR);
  525.          if (fd != -1)
  526.             fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
  527.       }
  528.    }
  529.    else {
  530.       fd = dup((int) pointer_to_intptr(dpy));
  531.    }
  532.    if (fd < 0)
  533.       return NULL;
  534.  
  535.    ndpy = fbdev_display_create(fd, fbdev_event_handler);
  536.    if (!ndpy)
  537.       close(fd);
  538.  
  539.    return ndpy;
  540. }
  541.  
  542. static const struct native_platform fbdev_platform = {
  543.    "FBDEV", /* name */
  544.    native_create_display
  545. };
  546.  
  547. const struct native_platform *
  548. native_get_fbdev_platform(const struct native_event_handler *event_handler)
  549. {
  550.    fbdev_event_handler = event_handler;
  551.    return &fbdev_platform;
  552. }
  553.