nvc0: make state handling race free
authorKarol Herbst <kherbst@redhat.com>
Thu, 17 Jun 2021 16:56:24 +0000 (18:56 +0200)
committerMarge Bot <emma+marge@anholt.net>
Tue, 30 Aug 2022 23:08:19 +0000 (23:08 +0000)
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 <kherbst@redhat.com>
Acked-by: M Henning <drawoc@darkrefraction.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10752>

src/gallium/drivers/nouveau/nvc0/nvc0_compute.c
src/gallium/drivers/nouveau/nvc0/nvc0_context.c
src/gallium/drivers/nouveau/nvc0/nvc0_program.c
src/gallium/drivers/nouveau/nvc0/nvc0_screen.c
src/gallium/drivers/nouveau/nvc0/nvc0_screen.h
src/gallium/drivers/nouveau/nvc0/nvc0_shader_state.c
src/gallium/drivers/nouveau/nvc0/nvc0_state.c
src/gallium/drivers/nouveau/nvc0/nvc0_state_validate.c
src/gallium/drivers/nouveau/nvc0/nvc0_surface.c
src/gallium/drivers/nouveau/nvc0/nvc0_vbo.c
src/gallium/drivers/nouveau/nvc0/nve4_compute.c

index 24ee9bf..b2b00f4 100644 (file)
@@ -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
index 1c90ba1..f718d0d 100644 (file)
@@ -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);
 
index 86dd155..36d0f70 100644 (file)
@@ -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);
index e6aac56..909e983 100644 (file)
@@ -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);
index 3af38b5..8bce90a 100644 (file)
@@ -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;
 
index 0bd8a75..b0715c7 100644 (file)
@@ -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))
index 08d2336..2f4a9c1 100644 (file)
@@ -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);
index 3fb69b5..6726b94 100644 (file)
@@ -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);
 
index 81b8332..2e7de27 100644 (file)
@@ -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);
 }
index d55792c..75c5080 100644 (file)
@@ -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);
index dccbce9..23d157f 100644 (file)
@@ -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");