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.tags/mesa-8.0-rc1
| @@ -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, | |||
| @@ -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); | |||
| @@ -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) / | |||
| @@ -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; | |||
| @@ -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, | |||
| @@ -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; | |||
| @@ -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 | |||
| @@ -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; | |||