Home | History | Annotate | Download | only in fbdev
      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 (at) lunarg.com>
     27  */
     28 
     29 #include <sys/mman.h>
     30 #include <sys/ioctl.h>
     31 #include <linux/fb.h>
     32 
     33 #include "pipe/p_compiler.h"
     34 #include "util/u_format.h"
     35 #include "util/u_math.h"
     36 #include "util/u_memory.h"
     37 #include "state_tracker/sw_winsys.h"
     38 
     39 #include "fbdev_sw_winsys.h"
     40 
     41 struct fbdev_sw_displaytarget
     42 {
     43    enum pipe_format format;
     44    unsigned width;
     45    unsigned height;
     46    unsigned stride;
     47 
     48    void *data;
     49    void *mapped;
     50 };
     51 
     52 struct fbdev_sw_winsys
     53 {
     54    struct sw_winsys base;
     55 
     56    int fd;
     57 
     58    struct fb_fix_screeninfo finfo;
     59    unsigned rows;
     60    unsigned stride;
     61 };
     62 
     63 static INLINE struct fbdev_sw_displaytarget *
     64 fbdev_sw_displaytarget(struct sw_displaytarget *dt)
     65 {
     66    return (struct fbdev_sw_displaytarget *) dt;
     67 }
     68 
     69 static INLINE struct fbdev_sw_winsys *
     70 fbdev_sw_winsys(struct sw_winsys *ws)
     71 {
     72    return (struct fbdev_sw_winsys *) ws;
     73 }
     74 
     75 static void
     76 fbdev_displaytarget_display(struct sw_winsys *ws,
     77                             struct sw_displaytarget *dt,
     78                             void *winsys_private)
     79 {
     80    struct fbdev_sw_winsys *fbdev = fbdev_sw_winsys(ws);
     81    struct fbdev_sw_displaytarget *src = fbdev_sw_displaytarget(dt);
     82    const struct fbdev_sw_drawable *dst =
     83       (const struct fbdev_sw_drawable *) winsys_private;
     84    unsigned height, row_offset, row_len, i;
     85    void *fbmem;
     86 
     87    /* FIXME format conversion */
     88    if (dst->format != src->format) {
     89       assert(0);
     90       return;
     91    }
     92 
     93    height = dst->height;
     94    if (dst->y + dst->height > fbdev->rows) {
     95       /* nothing to copy */
     96       if (dst->y >= fbdev->rows)
     97          return;
     98 
     99       height = fbdev->rows - dst->y;
    100    }
    101 
    102    row_offset = util_format_get_stride(dst->format, dst->x);
    103    row_len = util_format_get_stride(dst->format, dst->width);
    104    if (row_offset + row_len > fbdev->stride) {
    105       /* nothing to copy */
    106       if (row_offset >= fbdev->stride)
    107          return;
    108 
    109       row_len = fbdev->stride - row_offset;
    110    }
    111 
    112    fbmem = mmap(0, fbdev->finfo.smem_len,
    113          PROT_WRITE, MAP_SHARED, fbdev->fd, 0);
    114    if (fbmem == MAP_FAILED)
    115       return;
    116 
    117    for (i = 0; i < height; i++) {
    118       char *from = (char *) src->data + src->stride * i;
    119       char *to = (char *) fbmem + fbdev->stride * (dst->y + i) + row_offset;
    120 
    121       memcpy(to, from, row_len);
    122    }
    123 
    124    munmap(fbmem, fbdev->finfo.smem_len);
    125 }
    126 
    127 static void
    128 fbdev_displaytarget_unmap(struct sw_winsys *ws,
    129                            struct sw_displaytarget *dt)
    130 {
    131    struct fbdev_sw_displaytarget *fbdt = fbdev_sw_displaytarget(dt);
    132    fbdt->mapped = NULL;
    133 }
    134 
    135 static void *
    136 fbdev_displaytarget_map(struct sw_winsys *ws,
    137                         struct sw_displaytarget *dt,
    138                         unsigned flags)
    139 {
    140    struct fbdev_sw_displaytarget *fbdt = fbdev_sw_displaytarget(dt);
    141    fbdt->mapped = fbdt->data;
    142    return fbdt->mapped;
    143 }
    144 
    145 static void
    146 fbdev_displaytarget_destroy(struct sw_winsys *ws,
    147                             struct sw_displaytarget *dt)
    148 {
    149    struct fbdev_sw_displaytarget *fbdt = fbdev_sw_displaytarget(dt);
    150 
    151    if (fbdt->data)
    152       align_free(fbdt->data);
    153 
    154    FREE(fbdt);
    155 }
    156 
    157 static struct sw_displaytarget *
    158 fbdev_displaytarget_create(struct sw_winsys *ws,
    159                            unsigned tex_usage,
    160                            enum pipe_format format,
    161                            unsigned width, unsigned height,
    162                            unsigned alignment,
    163                            unsigned *stride)
    164 {
    165    struct fbdev_sw_displaytarget *fbdt;
    166    unsigned nblocksy, size, format_stride;
    167 
    168    fbdt = CALLOC_STRUCT(fbdev_sw_displaytarget);
    169    if (!fbdt)
    170       return NULL;
    171 
    172    fbdt->format = format;
    173    fbdt->width = width;
    174    fbdt->height = height;
    175 
    176    format_stride = util_format_get_stride(format, width);
    177    fbdt->stride = align(format_stride, alignment);
    178 
    179    nblocksy = util_format_get_nblocksy(format, height);
    180    size = fbdt->stride * nblocksy;
    181 
    182    fbdt->data = align_malloc(size, alignment);
    183    if (!fbdt->data) {
    184       FREE(fbdt);
    185       return NULL;
    186    }
    187 
    188    *stride = fbdt->stride;
    189 
    190    return (struct sw_displaytarget *) fbdt;
    191 }
    192 
    193 static boolean
    194 fbdev_is_displaytarget_format_supported(struct sw_winsys *ws,
    195                                         unsigned tex_usage,
    196                                         enum pipe_format format)
    197 {
    198    return TRUE;
    199 }
    200 
    201 static void
    202 fbdev_destroy(struct sw_winsys *ws)
    203 {
    204    struct fbdev_sw_winsys *fbdev = fbdev_sw_winsys(ws);
    205 
    206    FREE(fbdev);
    207 }
    208 
    209 struct sw_winsys *
    210 fbdev_create_sw_winsys(int fd)
    211 {
    212    struct fbdev_sw_winsys *fbdev;
    213 
    214    fbdev = CALLOC_STRUCT(fbdev_sw_winsys);
    215    if (!fbdev)
    216       return NULL;
    217 
    218    fbdev->fd = fd;
    219    if (ioctl(fbdev->fd, FBIOGET_FSCREENINFO, &fbdev->finfo)) {
    220       FREE(fbdev);
    221       return NULL;
    222    }
    223 
    224    fbdev->rows = fbdev->finfo.smem_len / fbdev->finfo.line_length;
    225    fbdev->stride = fbdev->finfo.line_length;
    226 
    227    fbdev->base.destroy = fbdev_destroy;
    228    fbdev->base.is_displaytarget_format_supported =
    229       fbdev_is_displaytarget_format_supported;
    230 
    231    fbdev->base.displaytarget_create = fbdev_displaytarget_create;
    232    fbdev->base.displaytarget_destroy = fbdev_displaytarget_destroy;
    233    fbdev->base.displaytarget_map = fbdev_displaytarget_map;
    234    fbdev->base.displaytarget_unmap = fbdev_displaytarget_unmap;
    235 
    236    fbdev->base.displaytarget_display = fbdev_displaytarget_display;
    237 
    238    return &fbdev->base;
    239 }
    240