gallium: Keep fenced buffers list ordered.
This allows to keep the list small without the overhead of full walks.
This commit is contained in:
@@ -62,7 +62,6 @@ struct fenced_buffer_list
|
|||||||
struct pipe_winsys *winsys;
|
struct pipe_winsys *winsys;
|
||||||
|
|
||||||
size_t numDelayed;
|
size_t numDelayed;
|
||||||
size_t checkDelayed;
|
|
||||||
|
|
||||||
struct list_head delayed;
|
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
|
static void
|
||||||
_fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list,
|
_fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list,
|
||||||
int wait)
|
int wait)
|
||||||
{
|
{
|
||||||
struct pipe_winsys *winsys = fenced_list->winsys;
|
struct pipe_winsys *winsys = fenced_list->winsys;
|
||||||
struct fenced_buffer *fenced_buf;
|
struct list_head *curr, *next;
|
||||||
struct list_head *list, *prev;
|
struct fenced_buffer *fenced_buf;
|
||||||
int signaled = -1;
|
struct pipe_fence_handle *prev_fence = NULL;
|
||||||
|
|
||||||
list = fenced_list->delayed.next;
|
curr = fenced_list->delayed.next;
|
||||||
prev = list->prev;
|
next = curr->next;
|
||||||
for (; list != &fenced_list->delayed; list = prev, prev = list->prev) {
|
while(curr != &fenced_list->delayed) {
|
||||||
|
fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
|
||||||
|
|
||||||
fenced_buf = LIST_ENTRY(struct fenced_buffer, list, head);
|
if(fenced_buf->fence != prev_fence) {
|
||||||
|
int signaled;
|
||||||
if (signaled != 0) {
|
if (wait)
|
||||||
if (wait) {
|
signaled = winsys->fence_finish(winsys, fenced_buf->fence, 0);
|
||||||
signaled = winsys->fence_finish(winsys, fenced_buf->fence, 0);
|
else
|
||||||
}
|
signaled = winsys->fence_signalled(winsys, fenced_buf->fence, 0);
|
||||||
else {
|
if (signaled != 0)
|
||||||
signaled = winsys->fence_signalled(winsys, fenced_buf->fence, 0);
|
break;
|
||||||
}
|
prev_fence = fenced_buf->fence;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signaled != 0) {
|
_fenced_buffer_remove(fenced_buf);
|
||||||
#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
|
|
||||||
}
|
|
||||||
|
|
||||||
winsys->fence_reference(winsys, &fenced_buf->fence, NULL);
|
curr = next;
|
||||||
|
next = curr->next;
|
||||||
LIST_DEL(list);
|
|
||||||
fenced_list->numDelayed--;
|
|
||||||
|
|
||||||
/* Do the delayed destroy:
|
|
||||||
*/
|
|
||||||
pb_reference(&fenced_buf->buffer, NULL);
|
|
||||||
FREE(fenced_buf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,25 +189,29 @@ fenced_buffer_destroy(struct pb_buffer *buf)
|
|||||||
struct fenced_buffer *fenced_buf = fenced_buffer(buf);
|
struct fenced_buffer *fenced_buf = fenced_buffer(buf);
|
||||||
struct fenced_buffer_list *fenced_list = fenced_buf->list;
|
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) {
|
if (fenced_buf->fence) {
|
||||||
struct pipe_winsys *winsys = fenced_list->winsys;
|
struct pipe_winsys *winsys = fenced_list->winsys;
|
||||||
if(winsys->fence_signalled(winsys, fenced_buf->fence, 0) != 0) {
|
if(winsys->fence_signalled(winsys, fenced_buf->fence, 0) == 0) {
|
||||||
LIST_ADDTAIL(&fenced_buf->head, &fenced_list->delayed);
|
struct list_head *curr, *prev;
|
||||||
fenced_list->numDelayed++;
|
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 {
|
else {
|
||||||
winsys->fence_reference(winsys, &fenced_buf->fence, NULL);
|
/* delay destruction */
|
||||||
pb_reference(&fenced_buf->buffer, NULL);
|
|
||||||
FREE(fenced_buf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pb_reference(&fenced_buf->buffer, NULL);
|
_fenced_buffer_destroy(fenced_buf);
|
||||||
FREE(fenced_buf);
|
|
||||||
}
|
}
|
||||||
|
_glthread_UNLOCK_MUTEX(fenced_list->mutex);
|
||||||
if ((fenced_list->numDelayed % fenced_list->checkDelayed) == 0)
|
|
||||||
_fenced_buffer_list_check_free(fenced_list, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -241,7 +286,11 @@ buffer_fence(struct pb_buffer *buf,
|
|||||||
struct pipe_winsys *winsys = fenced_list->winsys;
|
struct pipe_winsys *winsys = fenced_list->winsys;
|
||||||
|
|
||||||
_glthread_LOCK_MUTEX(fenced_list->mutex);
|
_glthread_LOCK_MUTEX(fenced_list->mutex);
|
||||||
|
if (fenced_buf->fence)
|
||||||
|
_fenced_buffer_remove(fenced_buf);
|
||||||
winsys->fence_reference(winsys, &fenced_buf->fence, fence);
|
winsys->fence_reference(winsys, &fenced_buf->fence, fence);
|
||||||
|
if (fenced_buf->fence)
|
||||||
|
_fenced_buffer_add(fenced_buf);
|
||||||
_glthread_UNLOCK_MUTEX(fenced_list->mutex);
|
_glthread_UNLOCK_MUTEX(fenced_list->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,9 +310,6 @@ fenced_buffer_list_create(struct pipe_winsys *winsys)
|
|||||||
|
|
||||||
fenced_list->numDelayed = 0;
|
fenced_list->numDelayed = 0;
|
||||||
|
|
||||||
/* TODO: don't hard code this */
|
|
||||||
fenced_list->checkDelayed = 5;
|
|
||||||
|
|
||||||
_glthread_INIT_MUTEX(fenced_list->mutex);
|
_glthread_INIT_MUTEX(fenced_list->mutex);
|
||||||
|
|
||||||
return fenced_list;
|
return fenced_list;
|
||||||
|
Reference in New Issue
Block a user