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