00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00037 #include "pipe/p_config.h"
00038
00039 #if defined(PIPE_OS_LINUX)
00040 #include <unistd.h>
00041 #include <sched.h>
00042 #endif
00043
00044 #include "pipe/p_compiler.h"
00045 #include "pipe/p_error.h"
00046 #include "pipe/p_debug.h"
00047 #include "pipe/p_winsys.h"
00048 #include "pipe/p_thread.h"
00049 #include "util/u_memory.h"
00050 #include "util/u_double_list.h"
00051
00052 #include "pb_buffer.h"
00053 #include "pb_buffer_fenced.h"
00054
00055
00056
00060 #define SUPER(__derived) (&(__derived)->base)
00061
00062 #define PIPE_BUFFER_USAGE_CPU_READ_WRITE \
00063 ( PIPE_BUFFER_USAGE_CPU_READ | PIPE_BUFFER_USAGE_CPU_WRITE )
00064 #define PIPE_BUFFER_USAGE_GPU_READ_WRITE \
00065 ( PIPE_BUFFER_USAGE_GPU_READ | PIPE_BUFFER_USAGE_GPU_WRITE )
00066 #define PIPE_BUFFER_USAGE_WRITE \
00067 ( PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_GPU_WRITE )
00068
00069
00070 struct fenced_buffer_list
00071 {
00072 pipe_mutex mutex;
00073
00074 struct pipe_winsys *winsys;
00075
00076 size_t numDelayed;
00077 struct list_head delayed;
00078
00079 #ifdef DEBUG
00080 size_t numUnfenced;
00081 struct list_head unfenced;
00082 #endif
00083 };
00084
00085
00089 struct fenced_buffer
00090 {
00091 struct pb_buffer base;
00092
00093 struct pb_buffer *buffer;
00094
00095
00096
00101 unsigned flags;
00102
00103 unsigned mapcount;
00104 struct pipe_fence_handle *fence;
00105
00106 struct list_head head;
00107 struct fenced_buffer_list *list;
00108 };
00109
00110
00111 static INLINE struct fenced_buffer *
00112 fenced_buffer(struct pb_buffer *buf)
00113 {
00114 assert(buf);
00115 assert(buf->vtbl == &fenced_buffer_vtbl);
00116 return (struct fenced_buffer *)buf;
00117 }
00118
00119
00120 static INLINE void
00121 _fenced_buffer_add(struct fenced_buffer *fenced_buf)
00122 {
00123 struct fenced_buffer_list *fenced_list = fenced_buf->list;
00124
00125 assert(fenced_buf->base.base.refcount);
00126 assert(fenced_buf->flags & PIPE_BUFFER_USAGE_GPU_READ_WRITE);
00127 assert(fenced_buf->fence);
00128
00129 #ifdef DEBUG
00130 LIST_DEL(&fenced_buf->head);
00131 assert(fenced_list->numUnfenced);
00132 --fenced_list->numUnfenced;
00133 #endif
00134 LIST_ADDTAIL(&fenced_buf->head, &fenced_list->delayed);
00135 ++fenced_list->numDelayed;
00136 }
00137
00138
00142 static INLINE void
00143 _fenced_buffer_destroy(struct fenced_buffer *fenced_buf)
00144 {
00145 struct fenced_buffer_list *fenced_list = fenced_buf->list;
00146
00147 assert(!fenced_buf->base.base.refcount);
00148 assert(!fenced_buf->fence);
00149 #ifdef DEBUG
00150 assert(fenced_buf->head.prev);
00151 assert(fenced_buf->head.next);
00152 LIST_DEL(&fenced_buf->head);
00153 assert(fenced_list->numUnfenced);
00154 --fenced_list->numUnfenced;
00155 #else
00156 (void)fenced_list;
00157 #endif
00158 pb_reference(&fenced_buf->buffer, NULL);
00159 FREE(fenced_buf);
00160 }
00161
00162
00163 static INLINE void
00164 _fenced_buffer_remove(struct fenced_buffer_list *fenced_list,
00165 struct fenced_buffer *fenced_buf)
00166 {
00167 struct pipe_winsys *winsys = fenced_list->winsys;
00168
00169 assert(fenced_buf->fence);
00170 assert(fenced_buf->list == fenced_list);
00171
00172 winsys->fence_reference(winsys, &fenced_buf->fence, NULL);
00173 fenced_buf->flags &= ~PIPE_BUFFER_USAGE_GPU_READ_WRITE;
00174
00175 assert(fenced_buf->head.prev);
00176 assert(fenced_buf->head.next);
00177
00178 LIST_DEL(&fenced_buf->head);
00179 assert(fenced_list->numDelayed);
00180 --fenced_list->numDelayed;
00181
00182 #ifdef DEBUG
00183 LIST_ADDTAIL(&fenced_buf->head, &fenced_list->unfenced);
00184 ++fenced_list->numUnfenced;
00185 #endif
00186
00187 if(!fenced_buf->base.base.refcount)
00188 _fenced_buffer_destroy(fenced_buf);
00189 }
00190
00191
00192 static INLINE enum pipe_error
00193 _fenced_buffer_finish(struct fenced_buffer *fenced_buf)
00194 {
00195 struct fenced_buffer_list *fenced_list = fenced_buf->list;
00196 struct pipe_winsys *winsys = fenced_list->winsys;
00197
00198 #if 0
00199 debug_warning("waiting for GPU");
00200 #endif
00201
00202 assert(fenced_buf->fence);
00203 if(fenced_buf->fence) {
00204 if(winsys->fence_finish(winsys, fenced_buf->fence, 0) != 0) {
00205 return PIPE_ERROR;
00206 }
00207
00208
00209 _fenced_buffer_remove(fenced_list, fenced_buf);
00210 }
00211
00212 fenced_buf->flags &= ~PIPE_BUFFER_USAGE_GPU_READ_WRITE;
00213 return PIPE_OK;
00214 }
00215
00216
00220 static void
00221 _fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list,
00222 int wait)
00223 {
00224 struct pipe_winsys *winsys = fenced_list->winsys;
00225 struct list_head *curr, *next;
00226 struct fenced_buffer *fenced_buf;
00227 struct pipe_fence_handle *prev_fence = NULL;
00228
00229 curr = fenced_list->delayed.next;
00230 next = curr->next;
00231 while(curr != &fenced_list->delayed) {
00232 fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
00233
00234 if(fenced_buf->fence != prev_fence) {
00235 int signaled;
00236 if (wait)
00237 signaled = winsys->fence_finish(winsys, fenced_buf->fence, 0);
00238 else
00239 signaled = winsys->fence_signalled(winsys, fenced_buf->fence, 0);
00240 if (signaled != 0)
00241 break;
00242 prev_fence = fenced_buf->fence;
00243 }
00244 else {
00245 assert(winsys->fence_signalled(winsys, fenced_buf->fence, 0) == 0);
00246 }
00247
00248 _fenced_buffer_remove(fenced_list, fenced_buf);
00249
00250 curr = next;
00251 next = curr->next;
00252 }
00253 }
00254
00255
00256 static void
00257 fenced_buffer_destroy(struct pb_buffer *buf)
00258 {
00259 struct fenced_buffer *fenced_buf = fenced_buffer(buf);
00260 struct fenced_buffer_list *fenced_list = fenced_buf->list;
00261
00262 pipe_mutex_lock(fenced_list->mutex);
00263 assert(fenced_buf->base.base.refcount == 0);
00264 if (fenced_buf->fence) {
00265 struct pipe_winsys *winsys = fenced_list->winsys;
00266 if(winsys->fence_signalled(winsys, fenced_buf->fence, 0) == 0) {
00267 struct list_head *curr, *prev;
00268 curr = &fenced_buf->head;
00269 prev = curr->prev;
00270 do {
00271 fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
00272 assert(winsys->fence_signalled(winsys, fenced_buf->fence, 0) == 0);
00273 _fenced_buffer_remove(fenced_list, fenced_buf);
00274 curr = prev;
00275 prev = curr->prev;
00276 } while (curr != &fenced_list->delayed);
00277 }
00278 else {
00279
00280 }
00281 }
00282 else {
00283 _fenced_buffer_destroy(fenced_buf);
00284 }
00285 pipe_mutex_unlock(fenced_list->mutex);
00286 }
00287
00288
00289 static void *
00290 fenced_buffer_map(struct pb_buffer *buf,
00291 unsigned flags)
00292 {
00293 struct fenced_buffer *fenced_buf = fenced_buffer(buf);
00294 struct fenced_buffer_list *fenced_list = fenced_buf->list;
00295 struct pipe_winsys *winsys = fenced_list->winsys;
00296 void *map;
00297
00298 assert(!(flags & PIPE_BUFFER_USAGE_GPU_READ_WRITE));
00299
00300
00301 if((fenced_buf->flags & PIPE_BUFFER_USAGE_GPU_WRITE) ||
00302 ((fenced_buf->flags & PIPE_BUFFER_USAGE_GPU_READ) && (flags & PIPE_BUFFER_USAGE_CPU_WRITE))) {
00303 if(flags & PIPE_BUFFER_USAGE_DONTBLOCK) {
00304
00305 if(winsys->fence_signalled(winsys, fenced_buf->fence, 0) == 0)
00306 _fenced_buffer_remove(fenced_list, fenced_buf);
00307 else
00308 return NULL;
00309 }
00310 else {
00311
00312 _fenced_buffer_finish(fenced_buf);
00313 }
00314 }
00315
00316 #if 0
00317
00318 if(fenced_buf->flags & PIPE_BUFFER_USAGE_CPU_READ_WRITE) {
00319
00320 debug_warning("concurrent CPU writes");
00321 }
00322 #endif
00323
00324 map = pb_map(fenced_buf->buffer, flags);
00325 if(map) {
00326 ++fenced_buf->mapcount;
00327 fenced_buf->flags |= flags & PIPE_BUFFER_USAGE_CPU_READ_WRITE;
00328 }
00329
00330 return map;
00331 }
00332
00333
00334 static void
00335 fenced_buffer_unmap(struct pb_buffer *buf)
00336 {
00337 struct fenced_buffer *fenced_buf = fenced_buffer(buf);
00338 assert(fenced_buf->mapcount);
00339 if(fenced_buf->mapcount) {
00340 pb_unmap(fenced_buf->buffer);
00341 --fenced_buf->mapcount;
00342 if(!fenced_buf->mapcount)
00343 fenced_buf->flags &= ~PIPE_BUFFER_USAGE_CPU_READ_WRITE;
00344 }
00345 }
00346
00347
00348 static void
00349 fenced_buffer_get_base_buffer(struct pb_buffer *buf,
00350 struct pb_buffer **base_buf,
00351 unsigned *offset)
00352 {
00353 struct fenced_buffer *fenced_buf = fenced_buffer(buf);
00354 pb_get_base_buffer(fenced_buf->buffer, base_buf, offset);
00355 }
00356
00357
00358 const struct pb_vtbl
00359 fenced_buffer_vtbl = {
00360 fenced_buffer_destroy,
00361 fenced_buffer_map,
00362 fenced_buffer_unmap,
00363 fenced_buffer_get_base_buffer
00364 };
00365
00366
00367 struct pb_buffer *
00368 fenced_buffer_create(struct fenced_buffer_list *fenced_list,
00369 struct pb_buffer *buffer)
00370 {
00371 struct fenced_buffer *buf;
00372
00373 if(!buffer)
00374 return NULL;
00375
00376 buf = CALLOC_STRUCT(fenced_buffer);
00377 if(!buf) {
00378 pb_reference(&buffer, NULL);
00379 return NULL;
00380 }
00381
00382 buf->base.base.refcount = 1;
00383 buf->base.base.alignment = buffer->base.alignment;
00384 buf->base.base.usage = buffer->base.usage;
00385 buf->base.base.size = buffer->base.size;
00386
00387 buf->base.vtbl = &fenced_buffer_vtbl;
00388 buf->buffer = buffer;
00389 buf->list = fenced_list;
00390
00391 #ifdef DEBUG
00392 pipe_mutex_lock(fenced_list->mutex);
00393 LIST_ADDTAIL(&buf->head, &fenced_list->unfenced);
00394 ++fenced_list->numUnfenced;
00395 pipe_mutex_unlock(fenced_list->mutex);
00396 #endif
00397
00398 return &buf->base;
00399 }
00400
00401
00402 void
00403 buffer_fence(struct pb_buffer *buf,
00404 struct pipe_fence_handle *fence)
00405 {
00406 struct fenced_buffer *fenced_buf;
00407 struct fenced_buffer_list *fenced_list;
00408 struct pipe_winsys *winsys;
00409
00410 unsigned flags = fence ? PIPE_BUFFER_USAGE_GPU_READ_WRITE : 0;
00411
00412
00413
00414
00415 assert(buf);
00416 if(!buf)
00417 return;
00418 assert(buf->vtbl == &fenced_buffer_vtbl);
00419 if(buf->vtbl != &fenced_buffer_vtbl)
00420 return;
00421
00422 if(!fence)
00423 return;
00424
00425 fenced_buf = fenced_buffer(buf);
00426 fenced_list = fenced_buf->list;
00427 winsys = fenced_list->winsys;
00428
00429 if(fence == fenced_buf->fence) {
00430 fenced_buf->flags |= flags & PIPE_BUFFER_USAGE_GPU_READ_WRITE;
00431 return;
00432 }
00433
00434 pipe_mutex_lock(fenced_list->mutex);
00435 if (fenced_buf->fence)
00436 _fenced_buffer_remove(fenced_list, fenced_buf);
00437 winsys->fence_reference(winsys, &fenced_buf->fence, fence);
00438 fenced_buf->flags |= flags & PIPE_BUFFER_USAGE_GPU_READ_WRITE;
00439 _fenced_buffer_add(fenced_buf);
00440 pipe_mutex_unlock(fenced_list->mutex);
00441 }
00442
00443
00444 struct fenced_buffer_list *
00445 fenced_buffer_list_create(struct pipe_winsys *winsys)
00446 {
00447 struct fenced_buffer_list *fenced_list;
00448
00449 fenced_list = CALLOC_STRUCT(fenced_buffer_list);
00450 if (!fenced_list)
00451 return NULL;
00452
00453 fenced_list->winsys = winsys;
00454
00455 LIST_INITHEAD(&fenced_list->delayed);
00456 fenced_list->numDelayed = 0;
00457
00458 #ifdef DEBUG
00459 LIST_INITHEAD(&fenced_list->unfenced);
00460 fenced_list->numUnfenced = 0;
00461 #endif
00462
00463 pipe_mutex_init(fenced_list->mutex);
00464
00465 return fenced_list;
00466 }
00467
00468
00469 void
00470 fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list,
00471 int wait)
00472 {
00473 pipe_mutex_lock(fenced_list->mutex);
00474 _fenced_buffer_list_check_free(fenced_list, wait);
00475 pipe_mutex_unlock(fenced_list->mutex);
00476 }
00477
00478
00479 #ifdef DEBUG
00480 void
00481 fenced_buffer_list_dump(struct fenced_buffer_list *fenced_list)
00482 {
00483 struct pipe_winsys *winsys = fenced_list->winsys;
00484 struct list_head *curr, *next;
00485 struct fenced_buffer *fenced_buf;
00486
00487 pipe_mutex_lock(fenced_list->mutex);
00488
00489 debug_printf("%10s %7s %10s %s\n",
00490 "buffer", "refcount", "fence", "signalled");
00491
00492 curr = fenced_list->unfenced.next;
00493 next = curr->next;
00494 while(curr != &fenced_list->unfenced) {
00495 fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
00496 assert(!fenced_buf->fence);
00497 debug_printf("%10p %7u\n",
00498 fenced_buf,
00499 fenced_buf->base.base.refcount);
00500 curr = next;
00501 next = curr->next;
00502 }
00503
00504 curr = fenced_list->delayed.next;
00505 next = curr->next;
00506 while(curr != &fenced_list->delayed) {
00507 int signaled;
00508 fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
00509 signaled = winsys->fence_signalled(winsys, fenced_buf->fence, 0);
00510 debug_printf("%10p %7u %10p %s\n",
00511 fenced_buf,
00512 fenced_buf->base.base.refcount,
00513 fenced_buf->fence,
00514 signaled == 0 ? "y" : "n");
00515 curr = next;
00516 next = curr->next;
00517 }
00518
00519 pipe_mutex_unlock(fenced_list->mutex);
00520 }
00521 #endif
00522
00523
00524 void
00525 fenced_buffer_list_destroy(struct fenced_buffer_list *fenced_list)
00526 {
00527 pipe_mutex_lock(fenced_list->mutex);
00528
00529
00530 while (fenced_list->numDelayed) {
00531 pipe_mutex_unlock(fenced_list->mutex);
00532 #if defined(PIPE_OS_LINUX)
00533 sched_yield();
00534 #endif
00535 _fenced_buffer_list_check_free(fenced_list, 1);
00536 pipe_mutex_lock(fenced_list->mutex);
00537 }
00538
00539 #ifdef DEBUG
00540
00541 #endif
00542
00543 pipe_mutex_unlock(fenced_list->mutex);
00544
00545 FREE(fenced_list);
00546 }
00547
00548