nouveau/fence: make the fence struct part of the fence API
This makes it easier to implement proper locking of the fence struct as we can redesign some of the functions to take the list object instead of fence objects. Signed-off-by: Karol Herbst <kherbst@redhat.com> Reviewed-by: M Henning <drawoc@darkrefraction.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10752>
This commit is contained in:
@@ -59,6 +59,7 @@ void
|
||||
nouveau_fence_emit(struct nouveau_fence *fence)
|
||||
{
|
||||
struct nouveau_screen *screen = fence->screen;
|
||||
struct nouveau_fence_list *fence_list = &screen->fence;
|
||||
|
||||
assert(fence->state != NOUVEAU_FENCE_STATE_EMITTING);
|
||||
if (fence->state >= NOUVEAU_FENCE_STATE_EMITTED)
|
||||
@@ -69,14 +70,14 @@ nouveau_fence_emit(struct nouveau_fence *fence)
|
||||
|
||||
++fence->ref;
|
||||
|
||||
if (screen->fence.tail)
|
||||
screen->fence.tail->next = fence;
|
||||
if (fence_list->tail)
|
||||
fence_list->tail->next = fence;
|
||||
else
|
||||
screen->fence.head = fence;
|
||||
fence_list->head = fence;
|
||||
|
||||
screen->fence.tail = fence;
|
||||
fence_list->tail = fence;
|
||||
|
||||
screen->fence.emit(&screen->base, &fence->sequence);
|
||||
fence_list->emit(&screen->base, &fence->sequence);
|
||||
|
||||
assert(fence->state == NOUVEAU_FENCE_STATE_EMITTING);
|
||||
fence->state = NOUVEAU_FENCE_STATE_EMITTED;
|
||||
@@ -86,19 +87,19 @@ void
|
||||
nouveau_fence_del(struct nouveau_fence *fence)
|
||||
{
|
||||
struct nouveau_fence *it;
|
||||
struct nouveau_screen *screen = fence->screen;
|
||||
struct nouveau_fence_list *fence_list = &fence->screen->fence;
|
||||
|
||||
if (fence->state == NOUVEAU_FENCE_STATE_EMITTED ||
|
||||
fence->state == NOUVEAU_FENCE_STATE_FLUSHED) {
|
||||
if (fence == screen->fence.head) {
|
||||
screen->fence.head = fence->next;
|
||||
if (!screen->fence.head)
|
||||
screen->fence.tail = NULL;
|
||||
if (fence == fence_list->head) {
|
||||
fence_list->head = fence->next;
|
||||
if (!fence_list->head)
|
||||
fence_list->tail = NULL;
|
||||
} else {
|
||||
for (it = screen->fence.head; it && it->next != fence; it = it->next);
|
||||
for (it = fence_list->head; it && it->next != fence; it = it->next);
|
||||
it->next = fence->next;
|
||||
if (screen->fence.tail == fence)
|
||||
screen->fence.tail = it;
|
||||
if (fence_list->tail == fence)
|
||||
fence_list->tail = it;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,18 +112,18 @@ nouveau_fence_del(struct nouveau_fence *fence)
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_fence_cleanup(struct nouveau_screen *screen)
|
||||
nouveau_fence_cleanup(struct nouveau_fence_list *fence_list)
|
||||
{
|
||||
if (screen->fence.current) {
|
||||
if (fence_list->current) {
|
||||
struct nouveau_fence *current = NULL;
|
||||
|
||||
/* nouveau_fence_wait will create a new current fence, so wait on the
|
||||
* _current_ one, and remove both.
|
||||
*/
|
||||
nouveau_fence_ref(screen->fence.current, ¤t);
|
||||
nouveau_fence_ref(fence_list->current, ¤t);
|
||||
nouveau_fence_wait(current, NULL);
|
||||
nouveau_fence_ref(NULL, ¤t);
|
||||
nouveau_fence_ref(NULL, &screen->fence.current);
|
||||
nouveau_fence_ref(NULL, &fence_list->current);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +132,8 @@ nouveau_fence_update(struct nouveau_screen *screen, bool flushed)
|
||||
{
|
||||
struct nouveau_fence *fence;
|
||||
struct nouveau_fence *next = NULL;
|
||||
u32 sequence = screen->fence.update(&screen->base);
|
||||
struct nouveau_fence_list *fence_list = &screen->fence;
|
||||
u32 sequence = fence_list->update(&screen->base);
|
||||
|
||||
/* If running under drm-shim, let all fences be signalled so things run to
|
||||
* completion (avoids a hang at the end of shader-db).
|
||||
@@ -139,11 +141,11 @@ nouveau_fence_update(struct nouveau_screen *screen, bool flushed)
|
||||
if (unlikely(screen->disable_fences))
|
||||
sequence = screen->fence.sequence;
|
||||
|
||||
if (screen->fence.sequence_ack == sequence)
|
||||
if (fence_list->sequence_ack == sequence)
|
||||
return;
|
||||
screen->fence.sequence_ack = sequence;
|
||||
fence_list->sequence_ack = sequence;
|
||||
|
||||
for (fence = screen->fence.head; fence; fence = next) {
|
||||
for (fence = fence_list->head; fence; fence = next) {
|
||||
next = fence->next;
|
||||
sequence = fence->sequence;
|
||||
|
||||
@@ -152,12 +154,12 @@ nouveau_fence_update(struct nouveau_screen *screen, bool flushed)
|
||||
nouveau_fence_trigger_work(fence);
|
||||
nouveau_fence_ref(NULL, &fence);
|
||||
|
||||
if (sequence == screen->fence.sequence_ack)
|
||||
if (sequence == fence_list->sequence_ack)
|
||||
break;
|
||||
}
|
||||
screen->fence.head = next;
|
||||
fence_list->head = next;
|
||||
if (!next)
|
||||
screen->fence.tail = NULL;
|
||||
fence_list->tail = NULL;
|
||||
|
||||
if (flushed) {
|
||||
for (fence = next; fence; fence = fence->next)
|
||||
@@ -186,6 +188,7 @@ static bool
|
||||
nouveau_fence_kick(struct nouveau_fence *fence)
|
||||
{
|
||||
struct nouveau_screen *screen = fence->screen;
|
||||
struct nouveau_fence_list *fence_list = &screen->fence;
|
||||
|
||||
/* wtf, someone is waiting on a fence in flush_notify handler? */
|
||||
assert(fence->state != NOUVEAU_FENCE_STATE_EMITTING);
|
||||
@@ -199,7 +202,7 @@ nouveau_fence_kick(struct nouveau_fence *fence)
|
||||
if (nouveau_pushbuf_kick(screen->pushbuf, screen->pushbuf->channel))
|
||||
return false;
|
||||
|
||||
if (fence == screen->fence.current)
|
||||
if (fence == fence_list->current)
|
||||
nouveau_fence_next(screen);
|
||||
|
||||
nouveau_fence_update(screen, false);
|
||||
@@ -211,6 +214,7 @@ bool
|
||||
nouveau_fence_wait(struct nouveau_fence *fence, struct util_debug_callback *debug)
|
||||
{
|
||||
struct nouveau_screen *screen = fence->screen;
|
||||
struct nouveau_fence_list *fence_list = &screen->fence;
|
||||
uint32_t spins = 0;
|
||||
int64_t start = 0;
|
||||
|
||||
@@ -241,7 +245,7 @@ nouveau_fence_wait(struct nouveau_fence *fence, struct util_debug_callback *debu
|
||||
|
||||
debug_printf("Wait on fence %u (ack = %u, next = %u) timed out !\n",
|
||||
fence->sequence,
|
||||
screen->fence.sequence_ack, screen->fence.sequence);
|
||||
fence_list->sequence_ack, fence_list->sequence);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -249,16 +253,18 @@ nouveau_fence_wait(struct nouveau_fence *fence, struct util_debug_callback *debu
|
||||
void
|
||||
nouveau_fence_next(struct nouveau_screen *screen)
|
||||
{
|
||||
if (screen->fence.current->state < NOUVEAU_FENCE_STATE_EMITTING) {
|
||||
if (screen->fence.current->ref > 1)
|
||||
nouveau_fence_emit(screen->fence.current);
|
||||
struct nouveau_fence_list *fence_list = &screen->fence;
|
||||
|
||||
if (fence_list->current->state < NOUVEAU_FENCE_STATE_EMITTING) {
|
||||
if (fence_list->current->ref > 1)
|
||||
nouveau_fence_emit(fence_list->current);
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
nouveau_fence_ref(NULL, &screen->fence.current);
|
||||
nouveau_fence_ref(NULL, &fence_list->current);
|
||||
|
||||
nouveau_fence_new(screen, &screen->fence.current);
|
||||
nouveau_fence_new(screen, &fence_list->current);
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -29,11 +29,21 @@ struct nouveau_fence {
|
||||
struct list_head work;
|
||||
};
|
||||
|
||||
struct nouveau_fence_list {
|
||||
struct nouveau_fence *head;
|
||||
struct nouveau_fence *tail;
|
||||
struct nouveau_fence *current;
|
||||
uint32_t sequence;
|
||||
uint32_t sequence_ack;
|
||||
void (*emit)(struct pipe_screen *, uint32_t *sequence);
|
||||
uint32_t (*update)(struct pipe_screen *);
|
||||
};
|
||||
|
||||
void nouveau_fence_emit(struct nouveau_fence *);
|
||||
void nouveau_fence_del(struct nouveau_fence *);
|
||||
|
||||
bool nouveau_fence_new(struct nouveau_screen *, struct nouveau_fence **);
|
||||
void nouveau_fence_cleanup(struct nouveau_screen *);
|
||||
void nouveau_fence_cleanup(struct nouveau_fence_list *);
|
||||
bool nouveau_fence_work(struct nouveau_fence *, void (*)(void *), void *);
|
||||
void nouveau_fence_update(struct nouveau_screen *, bool flushed);
|
||||
void nouveau_fence_next(struct nouveau_screen *);
|
||||
|
@@ -6,6 +6,8 @@
|
||||
#include "util/u_atomic.h"
|
||||
#include "util/u_memory.h"
|
||||
|
||||
#include "nouveau_fence.h"
|
||||
|
||||
#ifndef NDEBUG
|
||||
# define NOUVEAU_ENABLE_DRIVER_STATISTICS
|
||||
#endif
|
||||
@@ -44,15 +46,7 @@ struct nouveau_screen {
|
||||
|
||||
uint16_t class_3d;
|
||||
|
||||
struct {
|
||||
struct nouveau_fence *head;
|
||||
struct nouveau_fence *tail;
|
||||
struct nouveau_fence *current;
|
||||
u32 sequence;
|
||||
u32 sequence_ack;
|
||||
void (*emit)(struct pipe_screen *, u32 *sequence);
|
||||
u32 (*update)(struct pipe_screen *);
|
||||
} fence;
|
||||
struct nouveau_fence_list fence;
|
||||
|
||||
struct nouveau_mman *mm_VRAM;
|
||||
struct nouveau_mman *mm_GART;
|
||||
|
@@ -549,7 +549,7 @@ nv30_screen_destroy(struct pipe_screen *pscreen)
|
||||
if (!nouveau_drm_screen_unref(&screen->base))
|
||||
return;
|
||||
|
||||
nouveau_fence_cleanup(&screen->base);
|
||||
nouveau_fence_cleanup(&screen->base.fence);
|
||||
|
||||
nouveau_bo_ref(NULL, &screen->notify);
|
||||
|
||||
|
@@ -624,7 +624,7 @@ nv50_screen_destroy(struct pipe_screen *pscreen)
|
||||
if (!nouveau_drm_screen_unref(&screen->base))
|
||||
return;
|
||||
|
||||
nouveau_fence_cleanup(&screen->base);
|
||||
nouveau_fence_cleanup(&screen->base.fence);
|
||||
|
||||
if (screen->base.pushbuf)
|
||||
screen->base.pushbuf->user_priv = NULL;
|
||||
|
@@ -715,7 +715,7 @@ nvc0_screen_destroy(struct pipe_screen *pscreen)
|
||||
if (!nouveau_drm_screen_unref(&screen->base))
|
||||
return;
|
||||
|
||||
nouveau_fence_cleanup(&screen->base);
|
||||
nouveau_fence_cleanup(&screen->base.fence);
|
||||
|
||||
if (screen->base.pushbuf)
|
||||
screen->base.pushbuf->user_priv = NULL;
|
||||
|
Reference in New Issue
Block a user