Remove src/mesa and src/mesa/main from gallium source include paths.
[mesa.git] / src / gallium / winsys / dri / intel / intel_batchpool.c
1 /**************************************************************************
2 *
3 * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 *
26 *
27 **************************************************************************/
28 /*
29 * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
30 */
31
32 /**
33 * XXX NOTE: there are no intel dependencies in this file.
34 * Rename to dri_batchpool.c?
35 */
36
37 #include <xf86drm.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <errno.h>
41
42 #include "pipe/p_compiler.h"
43 #include "pipe/p_thread.h"
44
45 #include "dri_bufpool.h"
46 #include "dri_bufmgr.h"
47 #include "intel_batchpool.h"
48
49
50 typedef struct
51 {
52 drmMMListHead head;
53 struct _BPool *parent;
54 struct _DriFenceObject *fence;
55 unsigned long start;
56 int unfenced;
57 int mapped;
58 } BBuf;
59
60 typedef struct _BPool
61 {
62 _glthread_Mutex mutex;
63 unsigned long bufSize;
64 unsigned poolSize;
65 unsigned numFree;
66 unsigned numTot;
67 unsigned numDelayed;
68 unsigned checkDelayed;
69 drmMMListHead free;
70 drmMMListHead delayed;
71 drmMMListHead head;
72 drmBO kernelBO;
73 void *virtual;
74 BBuf *bufs;
75 } BPool;
76
77
78 static BPool *
79 createBPool(int fd, unsigned long bufSize, unsigned numBufs, unsigned flags,
80 unsigned checkDelayed)
81 {
82 BPool *p = (BPool *) malloc(sizeof(*p));
83 BBuf *buf;
84 int i;
85
86 if (!p)
87 return NULL;
88
89 p->bufs = (BBuf *) malloc(numBufs * sizeof(*p->bufs));
90 if (!p->bufs) {
91 free(p);
92 return NULL;
93 }
94
95 DRMINITLISTHEAD(&p->free);
96 DRMINITLISTHEAD(&p->head);
97 DRMINITLISTHEAD(&p->delayed);
98
99 p->numTot = numBufs;
100 p->numFree = numBufs;
101 p->bufSize = bufSize;
102 p->numDelayed = 0;
103 p->checkDelayed = checkDelayed;
104
105 _glthread_INIT_MUTEX(p->mutex);
106
107 if (drmBOCreate(fd, 0, numBufs * bufSize, 0, NULL, drm_bo_type_dc,
108 flags, DRM_BO_HINT_DONT_FENCE, &p->kernelBO)) {
109 free(p->bufs);
110 free(p);
111 return NULL;
112 }
113 if (drmBOMap(fd, &p->kernelBO, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0,
114 &p->virtual)) {
115 drmBODestroy(fd, &p->kernelBO);
116 free(p->bufs);
117 free(p);
118 return NULL;
119 }
120
121 /*
122 * We unmap the buffer so that we can validate it later. Note that this is
123 * just a synchronizing operation. The buffer will have a virtual mapping
124 * until it is destroyed.
125 */
126
127 drmBOUnmap(fd, &p->kernelBO);
128
129 buf = p->bufs;
130 for (i = 0; i < numBufs; ++i) {
131 buf->parent = p;
132 buf->fence = NULL;
133 buf->start = i * bufSize;
134 buf->mapped = 0;
135 buf->unfenced = 0;
136 DRMLISTADDTAIL(&buf->head, &p->free);
137 buf++;
138 }
139
140 return p;
141 }
142
143
144 static void
145 pool_checkFree(BPool * p, int wait)
146 {
147 drmMMListHead *list, *prev;
148 BBuf *buf;
149 int signaled = 0;
150 int i;
151
152 list = p->delayed.next;
153
154 if (p->numDelayed > 3) {
155 for (i = 0; i < p->numDelayed; i += 3) {
156 list = list->next;
157 }
158 }
159
160 prev = list->prev;
161 for (; list != &p->delayed; list = prev, prev = list->prev) {
162
163 buf = DRMLISTENTRY(BBuf, list, head);
164
165 if (!signaled) {
166 if (wait) {
167 driFenceFinish(buf->fence, DRM_FENCE_TYPE_EXE, 1);
168 signaled = 1;
169 }
170 else {
171 signaled = driFenceSignaled(buf->fence, DRM_FENCE_TYPE_EXE);
172 }
173 }
174
175 if (!signaled)
176 break;
177
178 driFenceUnReference(buf->fence);
179 buf->fence = NULL;
180 DRMLISTDEL(list);
181 p->numDelayed--;
182 DRMLISTADD(list, &p->free);
183 p->numFree++;
184 }
185 }
186
187 static void *
188 pool_create(struct _DriBufferPool *pool,
189 unsigned long size, unsigned flags, unsigned hint,
190 unsigned alignment)
191 {
192 BPool *p = (BPool *) pool->data;
193
194 drmMMListHead *item;
195
196 if (alignment && (alignment != 4096))
197 return NULL;
198
199 _glthread_LOCK_MUTEX(p->mutex);
200
201 if (p->numFree == 0)
202 pool_checkFree(p, TRUE);
203
204 if (p->numFree == 0) {
205 fprintf(stderr, "Out of fixed size buffer objects\n");
206 BM_CKFATAL(-ENOMEM);
207 }
208
209 item = p->free.next;
210
211 if (item == &p->free) {
212 fprintf(stderr, "Fixed size buffer pool corruption\n");
213 }
214
215 DRMLISTDEL(item);
216 --p->numFree;
217
218 _glthread_UNLOCK_MUTEX(p->mutex);
219 return (void *) DRMLISTENTRY(BBuf, item, head);
220 }
221
222
223 static int
224 pool_destroy(struct _DriBufferPool *pool, void *private)
225 {
226 BBuf *buf = (BBuf *) private;
227 BPool *p = buf->parent;
228
229 _glthread_LOCK_MUTEX(p->mutex);
230
231 if (buf->fence) {
232 DRMLISTADDTAIL(&buf->head, &p->delayed);
233 p->numDelayed++;
234 }
235 else {
236 buf->unfenced = 0;
237 DRMLISTADD(&buf->head, &p->free);
238 p->numFree++;
239 }
240
241 if ((p->numDelayed % p->checkDelayed) == 0)
242 pool_checkFree(p, 0);
243
244 _glthread_UNLOCK_MUTEX(p->mutex);
245 return 0;
246 }
247
248
249 static int
250 pool_map(struct _DriBufferPool *pool, void *private, unsigned flags,
251 int hint, void **virtual)
252 {
253
254 BBuf *buf = (BBuf *) private;
255 BPool *p = buf->parent;
256
257 _glthread_LOCK_MUTEX(p->mutex);
258
259 /*
260 * Currently Mesa doesn't have any condition variables to resolve this
261 * cleanly in a multithreading environment.
262 * We bail out instead.
263 */
264
265 if (buf->mapped) {
266 fprintf(stderr, "Trying to map already mapped buffer object\n");
267 BM_CKFATAL(-EINVAL);
268 }
269
270 #if 0
271 if (buf->unfenced && !(hint & DRM_BO_HINT_ALLOW_UNFENCED_MAP)) {
272 fprintf(stderr, "Trying to map an unfenced buffer object 0x%08x"
273 " 0x%08x %d\n", hint, flags, buf->start);
274 BM_CKFATAL(-EINVAL);
275 }
276
277 #endif
278
279 if (buf->fence) {
280 _glthread_UNLOCK_MUTEX(p->mutex);
281 return -EBUSY;
282 }
283
284 buf->mapped = TRUE;
285 *virtual = (unsigned char *) p->virtual + buf->start;
286 _glthread_UNLOCK_MUTEX(p->mutex);
287 return 0;
288 }
289
290 static int
291 pool_waitIdle(struct _DriBufferPool *pool, void *private, int lazy)
292 {
293 BBuf *buf = (BBuf *) private;
294 driFenceFinish(buf->fence, 0x0, lazy);
295 return 0;
296 }
297
298 static int
299 pool_unmap(struct _DriBufferPool *pool, void *private)
300 {
301 BBuf *buf = (BBuf *) private;
302
303 buf->mapped = 0;
304 return 0;
305 }
306
307 static unsigned long
308 pool_offset(struct _DriBufferPool *pool, void *private)
309 {
310 BBuf *buf = (BBuf *) private;
311 BPool *p = buf->parent;
312
313 return p->kernelBO.offset + buf->start;
314 }
315
316 static unsigned
317 pool_flags(struct _DriBufferPool *pool, void *private)
318 {
319 BPool *p = (BPool *) pool->data;
320
321 return p->kernelBO.flags;
322 }
323
324 static unsigned long
325 pool_size(struct _DriBufferPool *pool, void *private)
326 {
327 BPool *p = (BPool *) pool->data;
328
329 return p->bufSize;
330 }
331
332
333 static int
334 pool_fence(struct _DriBufferPool *pool, void *private,
335 struct _DriFenceObject *fence)
336 {
337 BBuf *buf = (BBuf *) private;
338 BPool *p = buf->parent;
339
340 _glthread_LOCK_MUTEX(p->mutex);
341 if (buf->fence) {
342 driFenceUnReference(buf->fence);
343 }
344 buf->fence = fence;
345 buf->unfenced = 0;
346 driFenceReference(buf->fence);
347 _glthread_UNLOCK_MUTEX(p->mutex);
348
349 return 0;
350 }
351
352 static drmBO *
353 pool_kernel(struct _DriBufferPool *pool, void *private)
354 {
355 BBuf *buf = (BBuf *) private;
356 BPool *p = buf->parent;
357
358 return &p->kernelBO;
359 }
360
361 static int
362 pool_validate(struct _DriBufferPool *pool, void *private)
363 {
364 BBuf *buf = (BBuf *) private;
365 BPool *p = buf->parent;
366 _glthread_LOCK_MUTEX(p->mutex);
367 buf->unfenced = TRUE;
368 _glthread_UNLOCK_MUTEX(p->mutex);
369 return 0;
370 }
371
372 static void
373 pool_takedown(struct _DriBufferPool *pool)
374 {
375 BPool *p = (BPool *) pool->data;
376
377 /*
378 * Wait on outstanding fences.
379 */
380
381 _glthread_LOCK_MUTEX(p->mutex);
382 while ((p->numFree < p->numTot) && p->numDelayed) {
383 _glthread_UNLOCK_MUTEX(p->mutex);
384 sched_yield();
385 pool_checkFree(p, TRUE);
386 _glthread_LOCK_MUTEX(p->mutex);
387 }
388
389 drmBODestroy(pool->fd, &p->kernelBO);
390 free(p->bufs);
391 _glthread_UNLOCK_MUTEX(p->mutex);
392 free(p);
393 free(pool);
394 }
395
396
397 struct _DriBufferPool *
398 driBatchPoolInit(int fd, unsigned flags,
399 unsigned long bufSize,
400 unsigned numBufs, unsigned checkDelayed)
401 {
402 struct _DriBufferPool *pool;
403
404 pool = (struct _DriBufferPool *) malloc(sizeof(*pool));
405 if (!pool)
406 return NULL;
407
408 pool->data = createBPool(fd, bufSize, numBufs, flags, checkDelayed);
409 if (!pool->data)
410 return NULL;
411
412 pool->fd = fd;
413 pool->map = &pool_map;
414 pool->unmap = &pool_unmap;
415 pool->destroy = &pool_destroy;
416 pool->offset = &pool_offset;
417 pool->flags = &pool_flags;
418 pool->size = &pool_size;
419 pool->create = &pool_create;
420 pool->fence = &pool_fence;
421 pool->kernel = &pool_kernel;
422 pool->validate = &pool_validate;
423 pool->waitIdle = &pool_waitIdle;
424 pool->setstatic = NULL;
425 pool->takeDown = &pool_takedown;
426 return pool;
427 }