Mesa (master): nv50, nvc0: add states mask to state validation function

Christoph Bumiller chrisbmr at kemper.freedesktop.org
Tue Aug 30 04:57:16 PDT 2011


Module: Mesa
Branch: master
Commit: 222b3ea653e5525a4afa57e6a2353335953012d4
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=222b3ea653e5525a4afa57e6a2353335953012d4

Author: Christoph Bumiller <e0425955 at student.tuwien.ac.at>
Date:   Sat Aug 27 20:49:36 2011 +0200

nv50,nvc0: add states mask to state validation function

This prevents null dereferences in validation of interdependent
state after a switch to a pipe context where we mark all state
as dirty but where not all state is valid / set yet.

---

 src/gallium/drivers/nv50/nv50_context.h        |    3 ++-
 src/gallium/drivers/nv50/nv50_state_validate.c |   15 +++++++++++----
 src/gallium/drivers/nv50/nv50_surface.c        |    8 ++------
 src/gallium/drivers/nv50/nv50_vbo.c            |    2 +-
 src/gallium/drivers/nvc0/nvc0_context.h        |    3 ++-
 src/gallium/drivers/nvc0/nvc0_state_validate.c |   15 ++++++++++-----
 src/gallium/drivers/nvc0/nvc0_surface.c        |    6 +-----
 src/gallium/drivers/nvc0/nvc0_vbo.c            |    3 ++-
 8 files changed, 31 insertions(+), 24 deletions(-)

diff --git a/src/gallium/drivers/nv50/nv50_context.h b/src/gallium/drivers/nv50/nv50_context.h
index 284db69..384ca8f 100644
--- a/src/gallium/drivers/nv50/nv50_context.h
+++ b/src/gallium/drivers/nv50/nv50_context.h
@@ -172,7 +172,8 @@ extern void nv50_init_state_functions(struct nv50_context *);
 
 /* nv50_state_validate.c */
 /* @words: check for space before emitting relocs */
-extern boolean nv50_state_validate(struct nv50_context *, unsigned words);
+extern boolean nv50_state_validate(struct nv50_context *, uint32_t state_mask,
+                                   unsigned space_words);
 
 /* nv50_surface.c */
 extern void nv50_clear(struct pipe_context *, unsigned buffers,
diff --git a/src/gallium/drivers/nv50/nv50_state_validate.c b/src/gallium/drivers/nv50/nv50_state_validate.c
index 44f2d25..369daf8 100644
--- a/src/gallium/drivers/nv50/nv50_state_validate.c
+++ b/src/gallium/drivers/nv50/nv50_state_validate.c
@@ -306,7 +306,11 @@ nv50_switch_pipe_context(struct nv50_context *ctx_to)
    if (!ctx_to->blend)
       ctx_to->dirty &= ~NV50_NEW_BLEND;
    if (!ctx_to->rast)
+#ifdef NV50_SCISSORS_CLIPPING
+      ctx_to->dirty &= ~(NV50_NEW_RASTERIZER | NV50_NEW_SCISSOR);
+#else
       ctx_to->dirty &= ~NV50_NEW_RASTERIZER;
+#endif
    if (!ctx_to->zsa)
       ctx_to->dirty &= ~NV50_NEW_ZSA;
 
@@ -350,21 +354,24 @@ static struct state_validate {
 #define validate_list_len (sizeof(validate_list) / sizeof(validate_list[0]))
 
 boolean
-nv50_state_validate(struct nv50_context *nv50, unsigned words)
+nv50_state_validate(struct nv50_context *nv50, uint32_t mask, unsigned words)
 {
+   uint32_t state_mask;
    unsigned i;
 
    if (nv50->screen->cur_ctx != nv50)
       nv50_switch_pipe_context(nv50);
 
-   if (nv50->dirty) {
+   state_mask = nv50->dirty & mask;
+
+   if (state_mask) {
       for (i = 0; i < validate_list_len; ++i) {
          struct state_validate *validate = &validate_list[i];
 
-         if (nv50->dirty & validate->states)
+         if (state_mask & validate->states)
             validate->func(nv50);
       }
-      nv50->dirty = 0;
+      nv50->dirty &= ~state_mask;
    }
 
    MARK_RING(nv50->screen->base.channel, words, 0);
diff --git a/src/gallium/drivers/nv50/nv50_surface.c b/src/gallium/drivers/nv50/nv50_surface.c
index 8bca900..57339f8 100644
--- a/src/gallium/drivers/nv50/nv50_surface.c
+++ b/src/gallium/drivers/nv50/nv50_surface.c
@@ -370,12 +370,10 @@ nv50_clear(struct pipe_context *pipe, unsigned buffers,
    struct nouveau_channel *chan = nv50->screen->base.channel;
    struct pipe_framebuffer_state *fb = &nv50->framebuffer;
    unsigned i;
-   const unsigned dirty = nv50->dirty;
    uint32_t mode = 0;
 
    /* don't need NEW_BLEND, COLOR_MASK doesn't affect CLEAR_BUFFERS */
-   nv50->dirty &= NV50_NEW_FRAMEBUFFER;
-   if (!nv50_state_validate(nv50, 9 + (fb->nr_cbufs * 2)))
+   if (!nv50_state_validate(nv50, NV50_NEW_FRAMEBUFFER, 9 + (fb->nr_cbufs * 2)))
       return;
 
    if (buffers & PIPE_CLEAR_COLOR && fb->nr_cbufs) {
@@ -408,8 +406,6 @@ nv50_clear(struct pipe_context *pipe, unsigned buffers,
       BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1);
       OUT_RING  (chan, (i << 6) | 0x3c);
    }
-
-   nv50->dirty = dirty & ~NV50_NEW_FRAMEBUFFER;
 }
 
 
@@ -851,7 +847,7 @@ nv50_resource_resolve(struct pipe_context *pipe,
 
    nv50_blitctx_prepare_state(blit);
 
-   nv50_state_validate(nv50, 36);
+   nv50_state_validate(nv50, ~0, 36);
 
    x_range =
       (float)(info->src.x1 - info->src.x0) /
diff --git a/src/gallium/drivers/nv50/nv50_vbo.c b/src/gallium/drivers/nv50/nv50_vbo.c
index 1c8347a..82ac35e 100644
--- a/src/gallium/drivers/nv50/nv50_vbo.c
+++ b/src/gallium/drivers/nv50/nv50_vbo.c
@@ -647,7 +647,7 @@ nv50_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
    if (nv50->vbo_user && !(nv50->dirty & (NV50_NEW_VERTEX | NV50_NEW_ARRAYS)))
       nv50_update_user_vbufs(nv50);
 
-   nv50_state_validate(nv50, 8); /* 8 as minimum, we use flush_notify here */
+   nv50_state_validate(nv50, ~0, 8); /* 8 as minimum, we use flush_notify */
 
    chan->flush_notify = nv50_draw_vbo_flush_notify;
 
diff --git a/src/gallium/drivers/nvc0/nvc0_context.h b/src/gallium/drivers/nvc0/nvc0_context.h
index bf89164..aa50df0 100644
--- a/src/gallium/drivers/nvc0/nvc0_context.h
+++ b/src/gallium/drivers/nvc0/nvc0_context.h
@@ -179,7 +179,8 @@ void nvc0_tfb_validate(struct nvc0_context *);
 extern void nvc0_init_state_functions(struct nvc0_context *);
 
 /* nvc0_state_validate.c */
-extern boolean nvc0_state_validate(struct nvc0_context *);
+extern boolean nvc0_state_validate(struct nvc0_context *, uint32_t state_mask,
+                                   unsigned space_words);
 
 /* nvc0_surface.c */
 extern void nvc0_clear(struct pipe_context *, unsigned buffers,
diff --git a/src/gallium/drivers/nvc0/nvc0_state_validate.c b/src/gallium/drivers/nvc0/nvc0_state_validate.c
index 968d7a7..2fca291 100644
--- a/src/gallium/drivers/nvc0/nvc0_state_validate.c
+++ b/src/gallium/drivers/nvc0/nvc0_state_validate.c
@@ -453,7 +453,7 @@ nvc0_switch_pipe_context(struct nvc0_context *ctx_to)
    if (!ctx_to->blend)
       ctx_to->dirty &= ~NVC0_NEW_BLEND;
    if (!ctx_to->rast)
-      ctx_to->dirty &= ~NVC0_NEW_RASTERIZER;
+      ctx_to->dirty &= ~(NVC0_NEW_RASTERIZER | NVC0_NEW_SCISSOR);
    if (!ctx_to->zsa)
       ctx_to->dirty &= ~NVC0_NEW_ZSA;
 
@@ -490,23 +490,28 @@ static struct state_validate {
 #define validate_list_len (sizeof(validate_list) / sizeof(validate_list[0]))
 
 boolean
-nvc0_state_validate(struct nvc0_context *nvc0)
+nvc0_state_validate(struct nvc0_context *nvc0, uint32_t mask, unsigned words)
 {
+   uint32_t state_mask;
    unsigned i;
 
    if (nvc0->screen->cur_ctx != nvc0)
       nvc0_switch_pipe_context(nvc0);
 
-   if (nvc0->dirty) {
+   state_mask = nvc0->dirty & mask;
+
+   if (state_mask) {
       for (i = 0; i < validate_list_len; ++i) {
          struct state_validate *validate = &validate_list[i];
 
-         if (nvc0->dirty & validate->states)
+         if (state_mask & validate->states)
             validate->func(nvc0);
       }
-      nvc0->dirty = 0;
+      nvc0->dirty &= ~state_mask;
    }
 
+   MARK_RING(nvc0->screen->base.channel, words, 0);
+
    nvc0_bufctx_emit_relocs(nvc0);
 
    return TRUE;
diff --git a/src/gallium/drivers/nvc0/nvc0_surface.c b/src/gallium/drivers/nvc0/nvc0_surface.c
index a4fd17e..385e2f0 100644
--- a/src/gallium/drivers/nvc0/nvc0_surface.c
+++ b/src/gallium/drivers/nvc0/nvc0_surface.c
@@ -383,12 +383,10 @@ nvc0_clear(struct pipe_context *pipe, unsigned buffers,
    struct nouveau_channel *chan = nvc0->screen->base.channel;
    struct pipe_framebuffer_state *fb = &nvc0->framebuffer;
    unsigned i;
-   const unsigned dirty = nvc0->dirty;
    uint32_t mode = 0;
 
    /* don't need NEW_BLEND, COLOR_MASK doesn't affect CLEAR_BUFFERS */
-   nvc0->dirty &= NVC0_NEW_FRAMEBUFFER;
-   if (!nvc0_state_validate(nvc0))
+   if (!nvc0_state_validate(nvc0, NVC0_NEW_FRAMEBUFFER, 9 + (fb->nr_cbufs * 2)))
       return;
 
    if (buffers & PIPE_CLEAR_COLOR && fb->nr_cbufs) {
@@ -421,8 +419,6 @@ nvc0_clear(struct pipe_context *pipe, unsigned buffers,
       BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1);
       OUT_RING  (chan, (i << 6) | 0x3c);
    }
-
-   nvc0->dirty = dirty & ~NVC0_NEW_FRAMEBUFFER;
 }
 
 void
diff --git a/src/gallium/drivers/nvc0/nvc0_vbo.c b/src/gallium/drivers/nvc0/nvc0_vbo.c
index 8a5bf8d..41b4552 100644
--- a/src/gallium/drivers/nvc0/nvc0_vbo.c
+++ b/src/gallium/drivers/nvc0/nvc0_vbo.c
@@ -584,7 +584,8 @@ nvc0_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
    if (nvc0->vbo_user && !(nvc0->dirty & (NVC0_NEW_VERTEX | NVC0_NEW_ARRAYS)))
       nvc0_update_user_vbufs(nvc0);
 
-   nvc0_state_validate(nvc0);
+   /* 8 as minimum to avoid immediate double validation of new buffers */
+   nvc0_state_validate(nvc0, ~0, 8);
 
    chan->flush_notify = nvc0_draw_vbo_flush_notify;
 



More information about the mesa-commit mailing list