Skip to content

Commit

Permalink
WIP nouveau: add locking
Browse files Browse the repository at this point in the history
  • Loading branch information
imirkin committed Jun 18, 2016
1 parent 54c03b9 commit be089dd
Show file tree
Hide file tree
Showing 30 changed files with 372 additions and 45 deletions.
29 changes: 24 additions & 5 deletions src/gallium/drivers/nouveau/nouveau_buffer.c
Expand Up @@ -380,6 +380,7 @@ nouveau_buffer_transfer_map(struct pipe_context *pipe,
struct pipe_transfer **ptransfer)
{
struct nouveau_context *nv = nouveau_context(pipe);
struct nouveau_screen *screen = nv->screen;
struct nv04_resource *buf = nv04_resource(resource);
struct nouveau_transfer *tx = MALLOC_STRUCT(nouveau_transfer);
uint8_t *map;
Expand Down Expand Up @@ -427,14 +428,19 @@ nouveau_buffer_transfer_map(struct pipe_context *pipe,
buf->data = NULL;
}
nouveau_transfer_staging(nv, tx, false);
pipe_mutex_lock(screen->push_mutex);
nouveau_transfer_read(nv, tx);
pipe_mutex_unlock(screen->push_mutex);
} else {
/* The buffer is currently idle. Create a staging area for writes,
* and make sure that the cached data is up-to-date. */
if (usage & PIPE_TRANSFER_WRITE)
nouveau_transfer_staging(nv, tx, true);
if (!buf->data)
if (!buf->data) {
pipe_mutex_lock(screen->push_mutex);
nouveau_buffer_cache(nv, buf);
pipe_mutex_unlock(screen->push_mutex);
}
}
}
return buf->data ? (buf->data + box->x) : tx->map;
Expand Down Expand Up @@ -479,7 +485,9 @@ nouveau_buffer_transfer_map(struct pipe_context *pipe,
if (unlikely(usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE)) {
/* Discarding was not possible, must sync because
* subsequent transfers might use UNSYNCHRONIZED. */
pipe_mutex_lock(screen->push_mutex);
nouveau_buffer_sync(nv, buf, usage & PIPE_TRANSFER_READ_WRITE);
pipe_mutex_unlock(screen->push_mutex);
} else
if (usage & PIPE_TRANSFER_DISCARD_RANGE) {
/* The whole range is being discarded, so it doesn't matter what was
Expand All @@ -488,10 +496,13 @@ nouveau_buffer_transfer_map(struct pipe_context *pipe,
map = tx->map;
} else
if (nouveau_buffer_busy(buf, PIPE_TRANSFER_READ)) {
if (usage & PIPE_TRANSFER_DONTBLOCK)
if (usage & PIPE_TRANSFER_DONTBLOCK) {
map = NULL;
else
} else {
pipe_mutex_lock(screen->push_mutex);
nouveau_buffer_sync(nv, buf, usage & PIPE_TRANSFER_READ_WRITE);
pipe_mutex_unlock(screen->push_mutex);
}
} else {
/* It is expected that the returned buffer be a representation of the
* data in question, so we must copy it over from the buffer. */
Expand All @@ -515,9 +526,13 @@ nouveau_buffer_transfer_flush_region(struct pipe_context *pipe,
{
struct nouveau_transfer *tx = nouveau_transfer(transfer);
struct nv04_resource *buf = nv04_resource(transfer->resource);
struct nouveau_screen *screen = nouveau_context(pipe)->screen;

if (tx->map)
if (tx->map) {
pipe_mutex_lock(screen->push_mutex);
nouveau_transfer_write(nouveau_context(pipe), tx, box->x, box->width);
pipe_mutex_unlock(screen->push_mutex);
}

util_range_add(&buf->valid_buffer_range,
tx->base.box.x + box->x,
Expand All @@ -537,11 +552,15 @@ nouveau_buffer_transfer_unmap(struct pipe_context *pipe,
struct nouveau_context *nv = nouveau_context(pipe);
struct nouveau_transfer *tx = nouveau_transfer(transfer);
struct nv04_resource *buf = nv04_resource(transfer->resource);
struct nouveau_screen *screen = nouveau_context(pipe)->screen;

if (tx->base.usage & PIPE_TRANSFER_WRITE) {
if (!(tx->base.usage & PIPE_TRANSFER_FLUSH_EXPLICIT)) {
if (tx->map)
if (tx->map) {
pipe_mutex_lock(screen->push_mutex);
nouveau_transfer_write(nv, tx, 0, tx->base.box.width);
pipe_mutex_unlock(screen->push_mutex);
}

util_range_add(&buf->valid_buffer_range,
tx->base.box.x, tx->base.box.x + tx->base.box.width);
Expand Down
18 changes: 18 additions & 0 deletions src/gallium/drivers/nouveau/nouveau_fence.c
Expand Up @@ -71,12 +71,14 @@ nouveau_fence_emit(struct nouveau_fence *fence)

++fence->ref;

pipe_mutex_lock(screen->fence.list_mutex);
if (screen->fence.tail)
screen->fence.tail->next = fence;
else
screen->fence.head = fence;

screen->fence.tail = fence;
pipe_mutex_unlock(screen->fence.list_mutex);

screen->fence.emit(&screen->base, &fence->sequence);

Expand All @@ -90,6 +92,9 @@ nouveau_fence_del(struct nouveau_fence *fence)
struct nouveau_fence *it;
struct nouveau_screen *screen = fence->screen;

/* XXX This can race against fence_update. But fence_update can also call
* into this, so ... be have to be careful.
*/
if (fence->state == NOUVEAU_FENCE_STATE_EMITTED ||
fence->state == NOUVEAU_FENCE_STATE_FLUSHED) {
if (fence == screen->fence.head) {
Expand Down Expand Up @@ -123,6 +128,7 @@ nouveau_fence_update(struct nouveau_screen *screen, bool flushed)
return;
screen->fence.sequence_ack = sequence;

pipe_mutex_lock(screen->fence.list_mutex);
for (fence = screen->fence.head; fence; fence = next) {
next = fence->next;
sequence = fence->sequence;
Expand All @@ -144,6 +150,7 @@ nouveau_fence_update(struct nouveau_screen *screen, bool flushed)
if (fence->state == NOUVEAU_FENCE_STATE_EMITTED)
fence->state = NOUVEAU_FENCE_STATE_FLUSHED;
}
pipe_mutex_unlock(screen->fence.list_mutex);
}

#define NOUVEAU_FENCE_MAX_SPINS (1 << 31)
Expand Down Expand Up @@ -198,18 +205,27 @@ nouveau_fence_wait(struct nouveau_fence *fence, struct pipe_debug_callback *debu
uint32_t spins = 0;
int64_t start = 0;

/* Fast-path for the case where the fence is already signaled to avoid
* messing around with mutexes and timing.
*/
if (fence->state == NOUVEAU_FENCE_STATE_SIGNALLED)
return true;

if (debug && debug->debug_message)
start = os_time_get_nano();

if (!nouveau_fence_kick(fence))
return false;

pipe_mutex_unlock(screen->push_mutex);

do {
if (fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) {
if (debug && debug->debug_message)
pipe_debug_message(debug, PERF_INFO,
"stalled %.3f ms waiting for fence",
(os_time_get_nano() - start) / 1000000.f);
pipe_mutex_lock(screen->push_mutex);
return true;
}
if (!spins)
Expand All @@ -227,6 +243,8 @@ nouveau_fence_wait(struct nouveau_fence *fence, struct pipe_debug_callback *debu
fence->sequence,
screen->fence.sequence_ack, screen->fence.sequence);

pipe_mutex_lock(screen->push_mutex);

return false;
}

Expand Down
5 changes: 3 additions & 2 deletions src/gallium/drivers/nouveau/nouveau_fence.h
Expand Up @@ -2,6 +2,7 @@
#ifndef __NOUVEAU_FENCE_H__
#define __NOUVEAU_FENCE_H__

#include "util/u_atomic.h"
#include "util/u_inlines.h"
#include "util/list.h"

Expand Down Expand Up @@ -47,10 +48,10 @@ static inline void
nouveau_fence_ref(struct nouveau_fence *fence, struct nouveau_fence **ref)
{
if (fence)
++fence->ref;
p_atomic_inc(&fence->ref);

if (*ref) {
if (--(*ref)->ref == 0)
if (p_atomic_dec_zero(&(*ref)->ref))
nouveau_fence_del(*ref);
}

Expand Down
12 changes: 11 additions & 1 deletion src/gallium/drivers/nouveau/nouveau_screen.c
Expand Up @@ -73,10 +73,14 @@ nouveau_screen_fence_finish(struct pipe_screen *screen,
struct pipe_fence_handle *pfence,
uint64_t timeout)
{
bool ret;
if (!timeout)
return nouveau_fence_signalled(nouveau_fence(pfence));

return nouveau_fence_wait(nouveau_fence(pfence), NULL);
pipe_mutex_lock(nouveau_screen(screen)->push_mutex);
ret = nouveau_fence_wait(nouveau_fence(pfence), NULL);
pipe_mutex_unlock(nouveau_screen(screen)->push_mutex);
return ret;
}


Expand Down Expand Up @@ -153,6 +157,9 @@ nouveau_screen_init(struct nouveau_screen *screen, struct nouveau_device *dev)
if (nv_dbg)
nouveau_mesa_debug = atoi(nv_dbg);

pipe_mutex_init(screen->push_mutex);
pipe_mutex_init(screen->fence.list_mutex);

/* These must be set before any failure is possible, as the cleanup
* paths assume they're responsible for deleting them.
*/
Expand Down Expand Up @@ -253,6 +260,9 @@ nouveau_screen_fini(struct nouveau_screen *screen)
nouveau_device_del(&screen->device);
nouveau_drm_del(&screen->drm);
close(fd);

pipe_mutex_destroy(screen->push_mutex);
pipe_mutex_destroy(screen->fence.list_mutex);
}

static void
Expand Down
3 changes: 3 additions & 0 deletions src/gallium/drivers/nouveau/nouveau_screen.h
Expand Up @@ -3,6 +3,7 @@

#include "pipe/p_screen.h"
#include "util/u_memory.h"
#include "os/os_thread.h"

#ifdef DEBUG
# define NOUVEAU_ENABLE_DRIVER_STATISTICS
Expand All @@ -22,6 +23,7 @@ struct nouveau_screen {
struct nouveau_object *channel;
struct nouveau_client *client;
struct nouveau_pushbuf *pushbuf;
pipe_mutex push_mutex;

int refcount;

Expand All @@ -39,6 +41,7 @@ struct nouveau_screen {
struct nouveau_fence *head;
struct nouveau_fence *tail;
struct nouveau_fence *current;
pipe_mutex list_mutex;
u32 sequence;
u32 sequence_ack;
void (*emit)(struct pipe_screen *, u32 *sequence);
Expand Down
22 changes: 19 additions & 3 deletions src/gallium/drivers/nouveau/nv30/nv30_clear.c
Expand Up @@ -58,8 +58,11 @@ nv30_clear(struct pipe_context *pipe, unsigned buffers,
struct pipe_framebuffer_state *fb = &nv30->framebuffer;
uint32_t colr = 0, zeta = 0, mode = 0;

if (!nv30_state_validate(nv30, NV30_NEW_FRAMEBUFFER | NV30_NEW_SCISSOR, true))
pipe_mutex_lock(nv30->screen->base.push_mutex);
if (!nv30_state_validate(nv30, NV30_NEW_FRAMEBUFFER | NV30_NEW_SCISSOR, true)) {
pipe_mutex_unlock(nv30->screen->base.push_mutex);
return;
}

if (buffers & PIPE_CLEAR_COLOR && fb->nr_cbufs) {
colr = pack_rgba(fb->cbufs[0]->format, color->f);
Expand Down Expand Up @@ -96,6 +99,7 @@ nv30_clear(struct pipe_context *pipe, unsigned buffers,
PUSH_DATA (push, mode);

nv30_state_release(nv30);
pipe_mutex_unlock(nv30->screen->base.push_mutex);
}

static void
Expand Down Expand Up @@ -125,11 +129,15 @@ nv30_clear_render_target(struct pipe_context *pipe, struct pipe_surface *ps,
rt_format |= NV30_3D_RT_FORMAT_TYPE_LINEAR;
}

pipe_mutex_lock(nv30->screen->base.push_mutex);

refn.bo = mt->base.bo;
refn.flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_WR;
if (nouveau_pushbuf_space(push, 16, 1, 0) ||
nouveau_pushbuf_refn (push, &refn, 1))
nouveau_pushbuf_refn (push, &refn, 1)) {
pipe_mutex_unlock(nv30->screen->base.push_mutex);
return;
}

BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1);
PUSH_DATA (push, NV30_3D_RT_ENABLE_COLOR0);
Expand All @@ -154,6 +162,8 @@ nv30_clear_render_target(struct pipe_context *pipe, struct pipe_surface *ps,
NV30_3D_CLEAR_BUFFERS_COLOR_B |
NV30_3D_CLEAR_BUFFERS_COLOR_A);

pipe_mutex_unlock(nv30->screen->base.push_mutex);

nv30->dirty |= NV30_NEW_FRAMEBUFFER | NV30_NEW_SCISSOR;
}

Expand Down Expand Up @@ -189,11 +199,15 @@ nv30_clear_depth_stencil(struct pipe_context *pipe, struct pipe_surface *ps,
if (buffers & PIPE_CLEAR_STENCIL)
mode |= NV30_3D_CLEAR_BUFFERS_STENCIL;

pipe_mutex_lock(nv30->screen->base.push_mutex);

refn.bo = mt->base.bo;
refn.flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_WR;
if (nouveau_pushbuf_space(push, 32, 1, 0) ||
nouveau_pushbuf_refn (push, &refn, 1))
nouveau_pushbuf_refn (push, &refn, 1)) {
pipe_mutex_unlock(nv30->screen->base.push_mutex);
return;
}

BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1);
PUSH_DATA (push, 0);
Expand All @@ -219,6 +233,8 @@ nv30_clear_depth_stencil(struct pipe_context *pipe, struct pipe_surface *ps,
BEGIN_NV04(push, NV30_3D(CLEAR_BUFFERS), 1);
PUSH_DATA (push, mode);

pipe_mutex_unlock(nv30->screen->base.push_mutex);

nv30->dirty |= NV30_NEW_FRAMEBUFFER | NV30_NEW_SCISSOR;
}

Expand Down
6 changes: 6 additions & 0 deletions src/gallium/drivers/nouveau/nv30/nv30_context.c
Expand Up @@ -201,6 +201,8 @@ nv30_context_create(struct pipe_screen *pscreen, void *priv, unsigned ctxflags)
if (!nv30)
return NULL;

pipe_mutex_lock(screen->base.push_mutex);

nv30->screen = screen;
nv30->base.screen = &screen->base;
nv30->base.copy_data = nv30_transfer_copy_data;
Expand All @@ -226,6 +228,7 @@ nv30_context_create(struct pipe_screen *pscreen, void *priv, unsigned ctxflags)
ret = nouveau_bufctx_new(nv30->base.client, 64, &nv30->bufctx);
if (ret) {
nv30_context_destroy(pipe);
pipe_mutex_unlock(screen->base.push_mutex);
return NULL;
}

Expand Down Expand Up @@ -259,10 +262,13 @@ nv30_context_create(struct pipe_screen *pscreen, void *priv, unsigned ctxflags)
nv30->blitter = util_blitter_create(pipe);
if (!nv30->blitter) {
nv30_context_destroy(pipe);
pipe_mutex_unlock(screen->base.push_mutex);
return NULL;
}

nouveau_context_init_vdec(&nv30->base);

pipe_mutex_unlock(screen->base.push_mutex);

return pipe;
}

0 comments on commit be089dd

Please sign in to comment.