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 #ifdef HAVE_SYS_SHM_H
30 #include <sys/ipc.h>
31 #include <sys/shm.h>
32 #ifdef __FreeBSD__
33 /* sys/ipc.h -> sys/_types.h -> machine/param.h
34  * - defines ALIGN which clashes with our ALIGN
35  */
36 #undef ALIGN
37 #endif
38 #endif
39 
40 #include "pipe/p_compiler.h"
41 #include "pipe/p_format.h"
42 #include "pipe/p_state.h"
43 #include "util/u_inlines.h"
44 #include "util/format/u_format.h"
45 #include "util/u_math.h"
46 #include "util/u_memory.h"
47 
48 #include "frontend/sw_winsys.h"
49 #include "dri_sw_winsys.h"
50 
51 
52 struct dri_sw_displaytarget
53 {
54    enum pipe_format format;
55    unsigned width;
56    unsigned height;
57    unsigned stride;
58 
59    unsigned map_flags;
60    int shmid;
61    void *data;
62    void *mapped;
63    const void *front_private;
64 };
65 
66 struct dri_sw_winsys
67 {
68    struct sw_winsys base;
69 
70    const struct drisw_loader_funcs *lf;
71 };
72 
73 static inline struct dri_sw_displaytarget *
dri_sw_displaytarget(struct sw_displaytarget * dt)74 dri_sw_displaytarget( struct sw_displaytarget *dt )
75 {
76    return (struct dri_sw_displaytarget *)dt;
77 }
78 
79 static inline struct dri_sw_winsys *
dri_sw_winsys(struct sw_winsys * ws)80 dri_sw_winsys( struct sw_winsys *ws )
81 {
82    return (struct dri_sw_winsys *)ws;
83 }
84 
85 
86 static bool
dri_sw_is_displaytarget_format_supported(struct sw_winsys * ws,unsigned tex_usage,enum pipe_format format)87 dri_sw_is_displaytarget_format_supported( struct sw_winsys *ws,
88                                           unsigned tex_usage,
89                                           enum pipe_format format )
90 {
91    /* TODO: check visuals or other sensible thing here */
92    return true;
93 }
94 
95 #ifdef HAVE_SYS_SHM_H
96 static char *
alloc_shm(struct dri_sw_displaytarget * dri_sw_dt,unsigned size)97 alloc_shm(struct dri_sw_displaytarget *dri_sw_dt, unsigned size)
98 {
99    char *addr;
100 
101    /* 0600 = user read+write */
102    dri_sw_dt->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600);
103    if (dri_sw_dt->shmid < 0)
104       return NULL;
105 
106    addr = (char *) shmat(dri_sw_dt->shmid, 0, 0);
107    /* mark the segment immediately for deletion to avoid leaks */
108    shmctl(dri_sw_dt->shmid, IPC_RMID, 0);
109 
110    if (addr == (char *) -1)
111       return NULL;
112 
113    return addr;
114 }
115 #endif
116 
117 static struct sw_displaytarget *
dri_sw_displaytarget_create(struct sw_winsys * winsys,unsigned tex_usage,enum pipe_format format,unsigned width,unsigned height,unsigned alignment,const void * front_private,unsigned * stride)118 dri_sw_displaytarget_create(struct sw_winsys *winsys,
119                             unsigned tex_usage,
120                             enum pipe_format format,
121                             unsigned width, unsigned height,
122                             unsigned alignment,
123                             const void *front_private,
124                             unsigned *stride)
125 {
126    struct dri_sw_winsys *ws = dri_sw_winsys(winsys);
127    struct dri_sw_displaytarget *dri_sw_dt;
128    unsigned nblocksy, size, format_stride;
129 
130    dri_sw_dt = CALLOC_STRUCT(dri_sw_displaytarget);
131    if(!dri_sw_dt)
132       goto no_dt;
133 
134    dri_sw_dt->format = format;
135    dri_sw_dt->width = width;
136    dri_sw_dt->height = height;
137    dri_sw_dt->front_private = front_private;
138 
139    format_stride = util_format_get_stride(format, width);
140    dri_sw_dt->stride = align(format_stride, alignment);
141 
142    nblocksy = util_format_get_nblocksy(format, height);
143    size = dri_sw_dt->stride * nblocksy;
144 
145    dri_sw_dt->shmid = -1;
146 
147 #ifdef HAVE_SYS_SHM_H
148    if (ws->lf->put_image_shm)
149       dri_sw_dt->data = alloc_shm(dri_sw_dt, size);
150 #endif
151 
152    if(!dri_sw_dt->data)
153       dri_sw_dt->data = align_malloc(size, alignment);
154 
155    if(!dri_sw_dt->data)
156       goto no_data;
157 
158    *stride = dri_sw_dt->stride;
159    return (struct sw_displaytarget *)dri_sw_dt;
160 
161 no_data:
162    FREE(dri_sw_dt);
163 no_dt:
164    return NULL;
165 }
166 
167 static void
dri_sw_displaytarget_destroy(struct sw_winsys * ws,struct sw_displaytarget * dt)168 dri_sw_displaytarget_destroy(struct sw_winsys *ws,
169                              struct sw_displaytarget *dt)
170 {
171    struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt);
172 
173    if (dri_sw_dt->shmid >= 0) {
174 #ifdef HAVE_SYS_SHM_H
175       shmdt(dri_sw_dt->data);
176       shmctl(dri_sw_dt->shmid, IPC_RMID, 0);
177 #endif
178    } else {
179       align_free(dri_sw_dt->data);
180    }
181 
182    FREE(dri_sw_dt);
183 }
184 
185 static void *
dri_sw_displaytarget_map(struct sw_winsys * ws,struct sw_displaytarget * dt,unsigned flags)186 dri_sw_displaytarget_map(struct sw_winsys *ws,
187                          struct sw_displaytarget *dt,
188                          unsigned flags)
189 {
190    struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt);
191    dri_sw_dt->mapped = dri_sw_dt->data;
192 
193    if (dri_sw_dt->front_private && (flags & PIPE_MAP_READ)) {
194       struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws);
195       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);
196    }
197    dri_sw_dt->map_flags = flags;
198    return dri_sw_dt->mapped;
199 }
200 
201 static void
dri_sw_displaytarget_unmap(struct sw_winsys * ws,struct sw_displaytarget * dt)202 dri_sw_displaytarget_unmap(struct sw_winsys *ws,
203                            struct sw_displaytarget *dt)
204 {
205    struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt);
206    if (dri_sw_dt->front_private && (dri_sw_dt->map_flags & PIPE_MAP_WRITE)) {
207       struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws);
208       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);
209    }
210    dri_sw_dt->map_flags = 0;
211    dri_sw_dt->mapped = NULL;
212 }
213 
214 static struct sw_displaytarget *
dri_sw_displaytarget_from_handle(struct sw_winsys * winsys,const struct pipe_resource * templ,struct winsys_handle * whandle,unsigned * stride)215 dri_sw_displaytarget_from_handle(struct sw_winsys *winsys,
216                                  const struct pipe_resource *templ,
217                                  struct winsys_handle *whandle,
218                                  unsigned *stride)
219 {
220    assert(0);
221    return NULL;
222 }
223 
224 static bool
dri_sw_displaytarget_get_handle(struct sw_winsys * winsys,struct sw_displaytarget * dt,struct winsys_handle * whandle)225 dri_sw_displaytarget_get_handle(struct sw_winsys *winsys,
226                                 struct sw_displaytarget *dt,
227                                 struct winsys_handle *whandle)
228 {
229    struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt);
230 
231    if (whandle->type == WINSYS_HANDLE_TYPE_SHMID) {
232       if (dri_sw_dt->shmid < 0)
233          return false;
234       whandle->handle = dri_sw_dt->shmid;
235       return true;
236    }
237 
238    return false;
239 }
240 
241 static void
dri_sw_displaytarget_display(struct sw_winsys * ws,struct sw_displaytarget * dt,void * context_private,struct pipe_box * box)242 dri_sw_displaytarget_display(struct sw_winsys *ws,
243                              struct sw_displaytarget *dt,
244                              void *context_private,
245                              struct pipe_box *box)
246 {
247    struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws);
248    struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt);
249    struct dri_drawable *dri_drawable = (struct dri_drawable *)context_private;
250    unsigned width, height, x = 0, y = 0;
251    unsigned blsize = util_format_get_blocksize(dri_sw_dt->format);
252    unsigned offset = 0;
253    unsigned offset_x = 0;
254    char *data = dri_sw_dt->data;
255    bool is_shm = dri_sw_dt->shmid != -1;
256    /* Set the width to 'stride / cpp'.
257     *
258     * PutImage correctly clips to the width of the dst drawable.
259     */
260    if (box) {
261       offset = dri_sw_dt->stride * box->y;
262       offset_x = box->x * blsize;
263       data += offset;
264       /* don't add x offset for shm, the put_image_shm will deal with it */
265       if (!is_shm)
266          data += offset_x;
267       x = box->x;
268       y = box->y;
269       width = box->width;
270       height = box->height;
271    } else {
272       width = dri_sw_dt->stride / blsize;
273       height = dri_sw_dt->height;
274    }
275 
276    if (is_shm) {
277       dri_sw_ws->lf->put_image_shm(dri_drawable, dri_sw_dt->shmid, dri_sw_dt->data, offset, offset_x,
278                                    x, y, width, height, dri_sw_dt->stride);
279       return;
280    }
281 
282    if (box)
283       dri_sw_ws->lf->put_image2(dri_drawable, data,
284                                 x, y, width, height, dri_sw_dt->stride);
285    else
286       dri_sw_ws->lf->put_image(dri_drawable, data, width, height);
287 }
288 
289 static void
dri_destroy_sw_winsys(struct sw_winsys * winsys)290 dri_destroy_sw_winsys(struct sw_winsys *winsys)
291 {
292    FREE(winsys);
293 }
294 
295 struct sw_winsys *
dri_create_sw_winsys(const struct drisw_loader_funcs * lf)296 dri_create_sw_winsys(const struct drisw_loader_funcs *lf)
297 {
298    struct dri_sw_winsys *ws;
299 
300    ws = CALLOC_STRUCT(dri_sw_winsys);
301    if (!ws)
302       return NULL;
303 
304    ws->lf = lf;
305    ws->base.destroy = dri_destroy_sw_winsys;
306 
307    ws->base.is_displaytarget_format_supported = dri_sw_is_displaytarget_format_supported;
308 
309    /* screen texture functions */
310    ws->base.displaytarget_create = dri_sw_displaytarget_create;
311    ws->base.displaytarget_destroy = dri_sw_displaytarget_destroy;
312    ws->base.displaytarget_from_handle = dri_sw_displaytarget_from_handle;
313    ws->base.displaytarget_get_handle = dri_sw_displaytarget_get_handle;
314 
315    /* texture functions */
316    ws->base.displaytarget_map = dri_sw_displaytarget_map;
317    ws->base.displaytarget_unmap = dri_sw_displaytarget_unmap;
318 
319    ws->base.displaytarget_display = dri_sw_displaytarget_display;
320 
321    return &ws->base;
322 }
323 
324 /* vim: set sw=3 ts=8 sts=3 expandtab: */
325