summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosé Fonseca <jrfonseca@tungstengraphics.com>2008-04-05 11:29:26 +0900
committerJosé Fonseca <jrfonseca@tungstengraphics.com>2008-04-05 13:45:41 +0900
commitfdff063343ddfbfb1b2fa921e2efcc2fae35d0ad (patch)
tree0093d73e1d717ad39a8c03edc1aa17e1e77e09a5
parentf1efef809caddff442ed45a59645b3f39498f521 (diff)
gallium: Keep fenced buffers list ordered.
This allows to keep the list small without the overhead of full walks.
-rw-r--r--src/gallium/auxiliary/pipebuffer/pb_buffer_fenced.c152
1 files changed, 99 insertions, 53 deletions
diff --git a/src/gallium/auxiliary/pipebuffer/pb_buffer_fenced.c b/src/gallium/auxiliary/pipebuffer/pb_buffer_fenced.c
index 1ecc7d42ee..24ba61a0b7 100644
--- a/src/gallium/auxiliary/pipebuffer/pb_buffer_fenced.c
+++ b/src/gallium/auxiliary/pipebuffer/pb_buffer_fenced.c
@@ -62,7 +62,6 @@ struct fenced_buffer_list
struct pipe_winsys *winsys;
size_t numDelayed;
- size_t checkDelayed;
struct list_head delayed;
};
@@ -93,51 +92,93 @@ fenced_buffer(struct pb_buffer *buf)
}
+static INLINE void
+_fenced_buffer_add(struct fenced_buffer *fenced_buf)
+{
+ struct fenced_buffer_list *fenced_list = fenced_buf->list;
+
+ assert(fenced_buf->fence);
+ assert(!fenced_buf->head.prev);
+ assert(!fenced_buf->head.next);
+ LIST_ADDTAIL(&fenced_buf->head, &fenced_list->delayed);
+ ++fenced_list->numDelayed;
+}
+
+
+/**
+ * Actually destroy the buffer.
+ */
+static INLINE void
+_fenced_buffer_destroy(struct fenced_buffer *fenced_buf)
+{
+ struct fenced_buffer_list *fenced_list = fenced_buf->list;
+
+ assert(!fenced_buf->base.base.refcount);
+ assert(!fenced_buf->fence);
+ pb_reference(&fenced_buf->buffer, NULL);
+ FREE(fenced_buf);
+}
+
+
+static INLINE void
+_fenced_buffer_remove(struct fenced_buffer *fenced_buf)
+{
+ struct fenced_buffer_list *fenced_list = fenced_buf->list;
+ struct pipe_winsys *winsys = fenced_list->winsys;
+
+ assert(fenced_buf->fence);
+
+ assert(winsys->fence_signalled(winsys, fenced_buf->fence, 0) == 0);
+ winsys->fence_reference(winsys, &fenced_buf->fence, NULL);
+
+ assert(fenced_buf->head.prev);
+ assert(fenced_buf->head.next);
+ LIST_DEL(&fenced_buf->head);
+#ifdef DEBUG
+ fenced_buf->head.prev = NULL;
+ fenced_buf->head.next = NULL;
+#endif
+
+ assert(fenced_list->numDelayed);
+ --fenced_list->numDelayed;
+
+ if(!fenced_buf->base.base.refcount)
+ _fenced_buffer_destroy(fenced_buf);
+}
+
+
+/**
+ * Free as many fenced buffers from the list head as possible.
+ */
static void
_fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list,
int wait)
{
struct pipe_winsys *winsys = fenced_list->winsys;
- struct fenced_buffer *fenced_buf;
- struct list_head *list, *prev;
- int signaled = -1;
-
- list = fenced_list->delayed.next;
- prev = list->prev;
- for (; list != &fenced_list->delayed; list = prev, prev = list->prev) {
-
- fenced_buf = LIST_ENTRY(struct fenced_buffer, list, head);
-
- if (signaled != 0) {
- if (wait) {
- signaled = winsys->fence_finish(winsys, fenced_buf->fence, 0);
- }
- else {
- signaled = winsys->fence_signalled(winsys, fenced_buf->fence, 0);
- }
+ struct list_head *curr, *next;
+ struct fenced_buffer *fenced_buf;
+ struct pipe_fence_handle *prev_fence = NULL;
+
+ curr = fenced_list->delayed.next;
+ next = curr->next;
+ while(curr != &fenced_list->delayed) {
+ fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
+
+ if(fenced_buf->fence != prev_fence) {
+ int signaled;
+ if (wait)
+ signaled = winsys->fence_finish(winsys, fenced_buf->fence, 0);
+ else
+ signaled = winsys->fence_signalled(winsys, fenced_buf->fence, 0);
+ if (signaled != 0)
+ break;
+ prev_fence = fenced_buf->fence;
}
- if (signaled != 0) {
-#if 0
- /* XXX: we are assuming that buffers are freed in the same order they
- * are fenced which may not always be true...
- */
- break;
-#else
- signaled = -1;
- continue;
-#endif
- }
+ _fenced_buffer_remove(fenced_buf);
- winsys->fence_reference(winsys, &fenced_buf->fence, NULL);
-
- LIST_DEL(list);
- fenced_list->numDelayed--;
-
- /* Do the delayed destroy:
- */
- pb_reference(&fenced_buf->buffer, NULL);
- FREE(fenced_buf);
+ curr = next;
+ next = curr->next;
}
}
@@ -148,25 +189,29 @@ fenced_buffer_destroy(struct pb_buffer *buf)
struct fenced_buffer *fenced_buf = fenced_buffer(buf);
struct fenced_buffer_list *fenced_list = fenced_buf->list;
+ _glthread_LOCK_MUTEX(fenced_list->mutex);
+ assert(fenced_buf->base.base.refcount == 0);
if (fenced_buf->fence) {
struct pipe_winsys *winsys = fenced_list->winsys;
- if(winsys->fence_signalled(winsys, fenced_buf->fence, 0) != 0) {
- LIST_ADDTAIL(&fenced_buf->head, &fenced_list->delayed);
- fenced_list->numDelayed++;
- }
+ if(winsys->fence_signalled(winsys, fenced_buf->fence, 0) == 0) {
+ struct list_head *curr, *prev;
+ curr = &fenced_buf->head;
+ prev = curr->prev;
+ do {
+ fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
+ _fenced_buffer_remove(fenced_buf);
+ curr = prev;
+ prev = curr->prev;
+ } while (curr != &fenced_list->delayed);
+ }
else {
- winsys->fence_reference(winsys, &fenced_buf->fence, NULL);
- pb_reference(&fenced_buf->buffer, NULL);
- FREE(fenced_buf);
+ /* delay destruction */
}
}
else {
- pb_reference(&fenced_buf->buffer, NULL);
- FREE(fenced_buf);
+ _fenced_buffer_destroy(fenced_buf);
}
-
- if ((fenced_list->numDelayed % fenced_list->checkDelayed) == 0)
- _fenced_buffer_list_check_free(fenced_list, 0);
+ _glthread_UNLOCK_MUTEX(fenced_list->mutex);
}
@@ -241,7 +286,11 @@ buffer_fence(struct pb_buffer *buf,
struct pipe_winsys *winsys = fenced_list->winsys;
_glthread_LOCK_MUTEX(fenced_list->mutex);
+ if (fenced_buf->fence)
+ _fenced_buffer_remove(fenced_buf);
winsys->fence_reference(winsys, &fenced_buf->fence, fence);
+ if (fenced_buf->fence)
+ _fenced_buffer_add(fenced_buf);
_glthread_UNLOCK_MUTEX(fenced_list->mutex);
}
@@ -261,9 +310,6 @@ fenced_buffer_list_create(struct pipe_winsys *winsys)
fenced_list->numDelayed = 0;
- /* TODO: don't hard code this */
- fenced_list->checkDelayed = 5;
-
_glthread_INIT_MUTEX(fenced_list->mutex);
return fenced_list;