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