From df0a4d02f264a4c49b7503c5f564ac4c492f906f Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Thu, 17 Jun 2021 18:56:24 +0200 Subject: [PATCH] nvc0: make state handling race free I am not entirely convinced that contexts can't mess up the state of other contexts, but with this we at least turn down the amount of races on the CPU side. If we hit bugs later we can always look into it then and figure out what to fix how. I think we might need a better solution for it in the future as state tracking might need to become more involved, but for now this should be good enough. Signed-off-by: Karol Herbst Acked-by: M Henning Part-of: --- src/gallium/drivers/nouveau/nvc0/nvc0_compute.c | 7 ++++++- src/gallium/drivers/nouveau/nvc0/nvc0_context.c | 5 +++++ src/gallium/drivers/nouveau/nvc0/nvc0_program.c | 6 +++++- src/gallium/drivers/nouveau/nvc0/nvc0_screen.c | 3 +++ src/gallium/drivers/nouveau/nvc0/nvc0_screen.h | 1 + .../drivers/nouveau/nvc0/nvc0_shader_state.c | 3 +++ src/gallium/drivers/nouveau/nvc0/nvc0_state.c | 3 +++ .../drivers/nouveau/nvc0/nvc0_state_validate.c | 3 +++ src/gallium/drivers/nouveau/nvc0/nvc0_surface.c | 16 ++++++++++++++-- src/gallium/drivers/nouveau/nvc0/nvc0_vbo.c | 6 ++++++ src/gallium/drivers/nouveau/nvc0/nve4_compute.c | 7 ++++++- 11 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_compute.c b/src/gallium/drivers/nouveau/nvc0/nvc0_compute.c index 24ee9bfff6c..b2b00f4ba98 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_compute.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_compute.c @@ -428,10 +428,11 @@ nvc0_launch_grid(struct pipe_context *pipe, const struct pipe_grid_info *info) struct nvc0_program *cp = nvc0->compprog; int ret; + simple_mtx_lock(&screen->state_lock); ret = !nvc0_state_validate_cp(nvc0, ~0); if (ret) { NOUVEAU_ERR("Failed to launch grid !\n"); - return; + goto out; } nvc0_compute_upload_input(nvc0, info); @@ -502,6 +503,10 @@ nvc0_launch_grid(struct pipe_context *pipe, const struct pipe_grid_info *info) nvc0->images_dirty[5] |= nvc0->images_valid[5]; nvc0_update_compute_invocations_counter(nvc0, info); + +out: + PUSH_KICK(push); + simple_mtx_unlock(&screen->state_lock); } static void diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_context.c b/src/gallium/drivers/nouveau/nvc0/nvc0_context.c index 1c90ba17853..f718d0d8fec 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_context.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_context.c @@ -243,11 +243,13 @@ nvc0_destroy(struct pipe_context *pipe) { struct nvc0_context *nvc0 = nvc0_context(pipe); + simple_mtx_lock(&nvc0->screen->state_lock); if (nvc0->screen->cur_ctx == nvc0) { nvc0->screen->cur_ctx = NULL; nvc0->screen->save_state = nvc0->state; nvc0->screen->save_state.tfb = NULL; } + simple_mtx_unlock(&nvc0->screen->state_lock); if (nvc0->base.pipe.stream_uploader) u_upload_destroy(nvc0->base.pipe.stream_uploader); @@ -493,10 +495,13 @@ nvc0_create(struct pipe_screen *pscreen, void *priv, unsigned ctxflags) /* now that there are no more opportunities for errors, set the current * context if there isn't already one. */ + simple_mtx_lock(&screen->state_lock); if (!screen->cur_ctx) { nvc0->state = screen->save_state; screen->cur_ctx = nvc0; } + simple_mtx_unlock(&screen->state_lock); + nouveau_pushbuf_bufctx(nvc0->base.pushbuf, nvc0->bufctx); PUSH_SPACE(nvc0->base.pushbuf, 8); diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_program.c b/src/gallium/drivers/nouveau/nvc0/nvc0_program.c index 86dd15520a5..36d0f7017c7 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_program.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_program.c @@ -884,6 +884,7 @@ nvc0_program_upload(struct nvc0_context *nvc0, struct nvc0_program *prog) size += TU102_SHADER_HEADER_SIZE; } + simple_mtx_assert_locked(&nvc0->screen->state_lock); ret = nvc0_program_alloc_code(nvc0, prog); if (ret) { struct nouveau_heap *heap = screen->text_heap; @@ -990,8 +991,11 @@ nvc0_program_destroy(struct nvc0_context *nvc0, struct nvc0_program *prog) const struct pipe_shader_state pipe = prog->pipe; const ubyte type = prog->type; - if (prog->mem) + if (prog->mem) { + if (nvc0) + simple_mtx_assert_locked(&nvc0->screen->state_lock); nouveau_heap_free(&prog->mem); + } FREE(prog->code); /* may be 0 for hardcoded shaders */ FREE(prog->relocs); FREE(prog->fixups); diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c index e6aac565bd2..909e983ed00 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c @@ -742,6 +742,7 @@ nvc0_screen_destroy(struct pipe_screen *pscreen) nouveau_object_del(&screen->nvsw); nouveau_screen_fini(&screen->base); + simple_mtx_destroy(&screen->state_lock); FREE(screen); } @@ -1068,6 +1069,8 @@ nvc0_screen_create(struct nouveau_device *dev) pscreen = &screen->base.base; pscreen->destroy = nvc0_screen_destroy; + simple_mtx_init(&screen->state_lock, mtx_plain); + ret = nouveau_screen_init(&screen->base, dev); if (ret) FAIL_SCREEN_INIT("Base screen init failed: %d\n", ret); diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.h b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.h index 3af38b59503..8bce90ae3af 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.h +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.h @@ -71,6 +71,7 @@ struct nvc0_screen { struct nvc0_context *cur_ctx; struct nvc0_graph_state save_state; + simple_mtx_t state_lock; int num_occlusion_queries_active; diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_shader_state.c b/src/gallium/drivers/nouveau/nvc0/nvc0_shader_state.c index 0bd8a752f15..b0715c7bfff 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_shader_state.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_shader_state.c @@ -71,6 +71,7 @@ nvc0_program_sp_start_id(struct nvc0_context *nvc0, int stage, { struct nouveau_pushbuf *push = nvc0->base.pushbuf; + simple_mtx_assert_locked(&nvc0->screen->state_lock); if (nvc0->screen->eng3d->oclass < GV100_3D_CLASS) { BEGIN_NVC0(push, NVC0_3D(SP_START_ID(stage)), 1); PUSH_DATA (push, prog->code_base); @@ -338,6 +339,8 @@ nvc0_tfb_validate(struct nvc0_context *nvc0) } } } + + simple_mtx_assert_locked(&nvc0->screen->state_lock); nvc0->state.tfb = tfb; if (!(nvc0->dirty_3d & NVC0_NEW_3D_TFB_TARGETS)) diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_state.c b/src/gallium/drivers/nouveau/nvc0/nvc0_state.c index 08d2336589f..2f4a9c117d2 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_state.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_state.c @@ -635,9 +635,12 @@ nvc0_sp_state_create(struct pipe_context *pipe, static void nvc0_sp_state_delete(struct pipe_context *pipe, void *hwcso) { + struct nvc0_context *nvc0 = nvc0_context(pipe); struct nvc0_program *prog = (struct nvc0_program *)hwcso; + simple_mtx_lock(&nvc0->screen->state_lock); nvc0_program_destroy(nvc0_context(pipe), prog); + simple_mtx_unlock(&nvc0->screen->state_lock); if (prog->pipe.type == PIPE_SHADER_IR_TGSI) FREE((void *)prog->pipe.tokens); diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_state_validate.c b/src/gallium/drivers/nouveau/nvc0/nvc0_state_validate.c index 3fb69b51208..6726b94587e 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_state_validate.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_state_validate.c @@ -872,6 +872,7 @@ nvc0_switch_pipe_context(struct nvc0_context *ctx_to) struct nvc0_context *ctx_from = ctx_to->screen->cur_ctx; unsigned s; + simple_mtx_assert_locked(&ctx_to->screen->state_lock); if (ctx_from) ctx_to->state = ctx_from->state; else @@ -968,6 +969,8 @@ nvc0_state_validate(struct nvc0_context *nvc0, uint32_t mask, int ret; unsigned i; + simple_mtx_assert_locked(&nvc0->screen->state_lock); + if (nvc0->screen->cur_ctx != nvc0) nvc0_switch_pipe_context(nvc0); diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_surface.c b/src/gallium/drivers/nouveau/nvc0/nvc0_surface.c index 81b833237f8..2e7de275252 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_surface.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_surface.c @@ -700,9 +700,11 @@ nvc0_clear(struct pipe_context *pipe, unsigned buffers, unsigned i, j, k; uint32_t mode = 0; + simple_mtx_lock(&nvc0->screen->state_lock); + /* don't need NEW_BLEND, COLOR_MASK doesn't affect CLEAR_BUFFERS */ if (!nvc0_state_validate_3d(nvc0, NVC0_NEW_3D_FRAMEBUFFER)) - return; + goto out; if (scissor_state) { uint32_t minx = scissor_state->minx; @@ -710,7 +712,7 @@ nvc0_clear(struct pipe_context *pipe, unsigned buffers, uint32_t miny = scissor_state->miny; uint32_t maxy = MIN2(fb->height, scissor_state->maxy); if (maxx <= minx || maxy <= miny) - return; + goto out; BEGIN_NVC0(push, NVC0_3D(SCREEN_SCISSOR_HORIZ), 2); PUSH_DATA (push, minx | (maxx - minx) << 16); @@ -781,6 +783,10 @@ nvc0_clear(struct pipe_context *pipe, unsigned buffers, PUSH_DATA (push, fb->width << 16); PUSH_DATA (push, fb->height << 16); } + +out: + PUSH_KICK(push); + simple_mtx_unlock(&nvc0->screen->state_lock); } static void @@ -789,8 +795,11 @@ gm200_evaluate_depth_buffer(struct pipe_context *pipe) struct nvc0_context *nvc0 = nvc0_context(pipe); struct nouveau_pushbuf *push = nvc0->base.pushbuf; + simple_mtx_lock(&nvc0->screen->state_lock); nvc0_state_validate_3d(nvc0, NVC0_NEW_3D_FRAMEBUFFER); IMMED_NVC0(push, SUBC_3D(0x11fc), 1); + PUSH_KICK(push); + simple_mtx_unlock(&nvc0->screen->state_lock); } @@ -1684,6 +1693,7 @@ nvc0_blit(struct pipe_context *pipe, const struct pipe_blit_info *info) if (info->num_window_rectangles > 0 || info->window_rectangle_include) eng3d = true; + simple_mtx_lock(&nvc0->screen->state_lock); if (nvc0->screen->num_occlusion_queries_active) IMMED_NVC0(push, NVC0_3D(SAMPLECNT_ENABLE), 0); @@ -1694,6 +1704,8 @@ nvc0_blit(struct pipe_context *pipe, const struct pipe_blit_info *info) if (nvc0->screen->num_occlusion_queries_active) IMMED_NVC0(push, NVC0_3D(SAMPLECNT_ENABLE), 1); + PUSH_KICK(push); + simple_mtx_unlock(&nvc0->screen->state_lock); NOUVEAU_DRV_STAT(&nvc0->screen->base, tex_blit_count, 1); } diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_vbo.c b/src/gallium/drivers/nouveau/nvc0/nvc0_vbo.c index d55792c44e8..75c5080fa77 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_vbo.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_vbo.c @@ -462,6 +462,7 @@ nvc0_vertex_arrays_validate(struct nvc0_context *nvc0) if (update_vertex) { const unsigned n = MAX2(vertex->num_elements, nvc0->state.num_vtxelts); + simple_mtx_assert_locked(&nvc0->screen->state_lock); nvc0->state.constant_vbos = const_vbos; nvc0->state.constant_elts = 0; nvc0->state.num_vtxelts = vertex->num_elements; @@ -1020,6 +1021,8 @@ nvc0_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info, BCTX_REFN_bo(nvc0->bufctx_3d, 3D_TEXT, vram_domain | NOUVEAU_BO_RD, screen->text); + simple_mtx_lock(&nvc0->screen->state_lock); + nvc0_state_validate_3d(nvc0, ~0); if (nvc0->vertprog->vp.need_draw_parameters && (!indirect || indirect->count_from_stream_output)) { @@ -1127,6 +1130,9 @@ nvc0_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info, } cleanup: + PUSH_KICK(push); + simple_mtx_unlock(&nvc0->screen->state_lock); + nvc0->base.kick_notify = nvc0_default_kick_notify; nvc0_release_user_vbufs(nvc0); diff --git a/src/gallium/drivers/nouveau/nvc0/nve4_compute.c b/src/gallium/drivers/nouveau/nvc0/nve4_compute.c index dccbce91ef7..23d157fd4bf 100644 --- a/src/gallium/drivers/nouveau/nvc0/nve4_compute.c +++ b/src/gallium/drivers/nouveau/nvc0/nve4_compute.c @@ -867,9 +867,10 @@ nve4_launch_grid(struct pipe_context *pipe, const struct pipe_grid_info *info) resident->flags); } + simple_mtx_lock(&screen->state_lock); ret = !nve4_state_validate_cp(nvc0, ~0); if (ret) - goto out; + goto out_unlock; if (nvc0->screen->compute->oclass >= GV100_COMPUTE_CLASS) gv100_compute_setup_launch_desc(nvc0, desc, info); @@ -934,6 +935,10 @@ nve4_launch_grid(struct pipe_context *pipe, const struct pipe_grid_info *info) nvc0_update_compute_invocations_counter(nvc0, info); +out_unlock: + PUSH_KICK(push); + simple_mtx_unlock(&screen->state_lock); + out: if (ret) NOUVEAU_ERR("Failed to launch grid !\n");