1/************************************************************************** 2 * 3 * Copyright 2009, VMware, Inc. 4 * All Rights Reserved. 5 * Copyright 2010 George Sapountzis <gsapountzis@gmail.com> 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sub license, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial portions 17 * of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 **************************************************************************/ 28 29#if !defined(ANDROID) || ANDROID_API_LEVEL >= 26 30/* Android's libc began supporting shm in Oreo */ 31#define HAVE_SHM 32#include <sys/ipc.h> 33#include <sys/shm.h> 34#endif 35 36#include "pipe/p_compiler.h" 37#include "pipe/p_format.h" 38#include "pipe/p_state.h" 39#include "util/u_inlines.h" 40#include "util/u_format.h" 41#include "util/u_math.h" 42#include "util/u_memory.h" 43 44#include "state_tracker/sw_winsys.h" 45#include "dri_sw_winsys.h" 46 47 48struct dri_sw_displaytarget 49{ 50 enum pipe_format format; 51 unsigned width; 52 unsigned height; 53 unsigned stride; 54 55 unsigned map_flags; 56 int shmid; 57 void *data; 58 void *mapped; 59 const void *front_private; 60}; 61 62struct dri_sw_winsys 63{ 64 struct sw_winsys base; 65 66 const struct drisw_loader_funcs *lf; 67}; 68 69static inline struct dri_sw_displaytarget * 70dri_sw_displaytarget( struct sw_displaytarget *dt ) 71{ 72 return (struct dri_sw_displaytarget *)dt; 73} 74 75static inline struct dri_sw_winsys * 76dri_sw_winsys( struct sw_winsys *ws ) 77{ 78 return (struct dri_sw_winsys *)ws; 79} 80 81 82static boolean 83dri_sw_is_displaytarget_format_supported( struct sw_winsys *ws, 84 unsigned tex_usage, 85 enum pipe_format format ) 86{ 87 /* TODO: check visuals or other sensible thing here */ 88 return TRUE; 89} 90 91#ifdef HAVE_SHM 92static char * 93alloc_shm(struct dri_sw_displaytarget *dri_sw_dt, unsigned size) 94{ 95 char *addr; 96 97 /* 0600 = user read+write */ 98 dri_sw_dt->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600); 99 if (dri_sw_dt->shmid < 0) 100 return NULL; 101 102 addr = (char *) shmat(dri_sw_dt->shmid, 0, 0); 103 /* mark the segment immediately for deletion to avoid leaks */ 104 shmctl(dri_sw_dt->shmid, IPC_RMID, 0); 105 106 if (addr == (char *) -1) 107 return NULL; 108 109 return addr; 110} 111#endif 112 113static struct sw_displaytarget * 114dri_sw_displaytarget_create(struct sw_winsys *winsys, 115 unsigned tex_usage, 116 enum pipe_format format, 117 unsigned width, unsigned height, 118 unsigned alignment, 119 const void *front_private, 120 unsigned *stride) 121{ 122 struct dri_sw_winsys *ws = dri_sw_winsys(winsys); 123 struct dri_sw_displaytarget *dri_sw_dt; 124 unsigned nblocksy, size, format_stride; 125 126 dri_sw_dt = CALLOC_STRUCT(dri_sw_displaytarget); 127 if(!dri_sw_dt) 128 goto no_dt; 129 130 dri_sw_dt->format = format; 131 dri_sw_dt->width = width; 132 dri_sw_dt->height = height; 133 dri_sw_dt->front_private = front_private; 134 135 format_stride = util_format_get_stride(format, width); 136 dri_sw_dt->stride = align(format_stride, alignment); 137 138 nblocksy = util_format_get_nblocksy(format, height); 139 size = dri_sw_dt->stride * nblocksy; 140 141 dri_sw_dt->shmid = -1; 142 143#ifdef HAVE_SHM 144 if (ws->lf->put_image_shm) 145 dri_sw_dt->data = alloc_shm(dri_sw_dt, size); 146#endif 147 148 if(!dri_sw_dt->data) 149 dri_sw_dt->data = align_malloc(size, alignment); 150 151 if(!dri_sw_dt->data) 152 goto no_data; 153 154 *stride = dri_sw_dt->stride; 155 return (struct sw_displaytarget *)dri_sw_dt; 156 157no_data: 158 FREE(dri_sw_dt); 159no_dt: 160 return NULL; 161} 162 163static void 164dri_sw_displaytarget_destroy(struct sw_winsys *ws, 165 struct sw_displaytarget *dt) 166{ 167 struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt); 168 169 if (dri_sw_dt->shmid >= 0) { 170#ifdef HAVE_SHM 171 shmdt(dri_sw_dt->data); 172 shmctl(dri_sw_dt->shmid, IPC_RMID, 0); 173#endif 174 } else { 175 align_free(dri_sw_dt->data); 176 } 177 178 FREE(dri_sw_dt); 179} 180 181static void * 182dri_sw_displaytarget_map(struct sw_winsys *ws, 183 struct sw_displaytarget *dt, 184 unsigned flags) 185{ 186 struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt); 187 dri_sw_dt->mapped = dri_sw_dt->data; 188 189 if (dri_sw_dt->front_private && (flags & PIPE_TRANSFER_READ)) { 190 struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws); 191 dri_sw_ws->lf->get_image((void *)dri_sw_dt->front_private, 0, 0, dri_sw_dt->width, dri_sw_dt->height, dri_sw_dt->stride, dri_sw_dt->data); 192 } 193 dri_sw_dt->map_flags = flags; 194 return dri_sw_dt->mapped; 195} 196 197static void 198dri_sw_displaytarget_unmap(struct sw_winsys *ws, 199 struct sw_displaytarget *dt) 200{ 201 struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt); 202 if (dri_sw_dt->front_private && (dri_sw_dt->map_flags & PIPE_TRANSFER_WRITE)) { 203 struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws); 204 dri_sw_ws->lf->put_image2((void *)dri_sw_dt->front_private, dri_sw_dt->data, 0, 0, dri_sw_dt->width, dri_sw_dt->height, dri_sw_dt->stride); 205 } 206 dri_sw_dt->map_flags = 0; 207 dri_sw_dt->mapped = NULL; 208} 209 210static struct sw_displaytarget * 211dri_sw_displaytarget_from_handle(struct sw_winsys *winsys, 212 const struct pipe_resource *templ, 213 struct winsys_handle *whandle, 214 unsigned *stride) 215{ 216 assert(0); 217 return NULL; 218} 219 220static boolean 221dri_sw_displaytarget_get_handle(struct sw_winsys *winsys, 222 struct sw_displaytarget *dt, 223 struct winsys_handle *whandle) 224{ 225 struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt); 226 227 if (whandle->type == WINSYS_HANDLE_TYPE_SHMID) { 228 if (dri_sw_dt->shmid < 0) 229 return FALSE; 230 whandle->handle = dri_sw_dt->shmid; 231 return TRUE; 232 } 233 234 return FALSE; 235} 236 237static void 238dri_sw_displaytarget_display(struct sw_winsys *ws, 239 struct sw_displaytarget *dt, 240 void *context_private, 241 struct pipe_box *box) 242{ 243 struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws); 244 struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt); 245 struct dri_drawable *dri_drawable = (struct dri_drawable *)context_private; 246 unsigned width, height, x = 0, y = 0; 247 unsigned blsize = util_format_get_blocksize(dri_sw_dt->format); 248 unsigned offset = 0; 249 unsigned offset_x = 0; 250 char *data = dri_sw_dt->data; 251 bool is_shm = dri_sw_dt->shmid != -1; 252 /* Set the width to 'stride / cpp'. 253 * 254 * PutImage correctly clips to the width of the dst drawable. 255 */ 256 if (box) { 257 offset = dri_sw_dt->stride * box->y; 258 offset_x = box->x * blsize; 259 data += offset; 260 /* don't add x offset for shm, the put_image_shm will deal with it */ 261 if (!is_shm) 262 data += offset_x; 263 x = box->x; 264 y = box->y; 265 width = box->width; 266 height = box->height; 267 } else { 268 width = dri_sw_dt->stride / blsize; 269 height = dri_sw_dt->height; 270 } 271 272 if (is_shm) { 273 dri_sw_ws->lf->put_image_shm(dri_drawable, dri_sw_dt->shmid, dri_sw_dt->data, offset, offset_x, 274 x, y, width, height, dri_sw_dt->stride); 275 return; 276 } 277 278 if (box) 279 dri_sw_ws->lf->put_image2(dri_drawable, data, 280 x, y, width, height, dri_sw_dt->stride); 281 else 282 dri_sw_ws->lf->put_image(dri_drawable, data, width, height); 283} 284 285static void 286dri_destroy_sw_winsys(struct sw_winsys *winsys) 287{ 288 FREE(winsys); 289} 290 291struct sw_winsys * 292dri_create_sw_winsys(const struct drisw_loader_funcs *lf) 293{ 294 struct dri_sw_winsys *ws; 295 296 ws = CALLOC_STRUCT(dri_sw_winsys); 297 if (!ws) 298 return NULL; 299 300 ws->lf = lf; 301 ws->base.destroy = dri_destroy_sw_winsys; 302 303 ws->base.is_displaytarget_format_supported = dri_sw_is_displaytarget_format_supported; 304 305 /* screen texture functions */ 306 ws->base.displaytarget_create = dri_sw_displaytarget_create; 307 ws->base.displaytarget_destroy = dri_sw_displaytarget_destroy; 308 ws->base.displaytarget_from_handle = dri_sw_displaytarget_from_handle; 309 ws->base.displaytarget_get_handle = dri_sw_displaytarget_get_handle; 310 311 /* texture functions */ 312 ws->base.displaytarget_map = dri_sw_displaytarget_map; 313 ws->base.displaytarget_unmap = dri_sw_displaytarget_unmap; 314 315 ws->base.displaytarget_display = dri_sw_displaytarget_display; 316 317 return &ws->base; 318} 319 320/* vim: set sw=3 ts=8 sts=3 expandtab: */ 321