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