diff --git a/src/mesa/state_tracker/st_atom.c b/src/mesa/state_tracker/st_atom.c index df2c5895fe7..555b375ea46 100644 --- a/src/mesa/state_tracker/st_atom.c +++ b/src/mesa/state_tracker/st_atom.c @@ -95,6 +95,7 @@ static void check_program_state( struct st_context *st ) * properly when transitioning to shaders that don't use them. */ if (unlikely(new_vp != (old_vp ? &old_vp->Base : NULL))) { + ctx->Array.NewVertexElements = true; if (old_vp) dirty |= old_vp->affected_states; if (new_vp) diff --git a/src/mesa/state_tracker/st_atom_array.cpp b/src/mesa/state_tracker/st_atom_array.cpp index 59a38931a05..6978074c543 100644 --- a/src/mesa/state_tracker/st_atom_array.cpp +++ b/src/mesa/state_tracker/st_atom_array.cpp @@ -50,6 +50,11 @@ #include "main/varray.h" #include "main/arrayobj.h" +enum st_update_flag { + UPDATE_ALL, + UPDATE_BUFFERS_ONLY, +}; + /* Always inline the non-64bit element code, so that the compiler can see * that velements is on the stack. */ @@ -70,7 +75,7 @@ init_velement(struct pipe_vertex_element *velements, /* ALWAYS_INLINE helps the compiler realize that most of the parameters are * on the stack. */ -template static void ALWAYS_INLINE +template void ALWAYS_INLINE setup_arrays(struct st_context *st, const struct gl_vertex_array_object *vao, const GLbitfield dual_slot_inputs, @@ -115,6 +120,9 @@ setup_arrays(struct st_context *st, } vbuffer[bufidx].stride = binding->Stride; /* in bytes */ + if (UPDATE == UPDATE_BUFFERS_ONLY) + continue; + /* Set the vertex element. */ init_velement(velements->velems, &attrib->Format, 0, binding->InstanceDivisor, bufidx, @@ -152,6 +160,10 @@ setup_arrays(struct st_context *st, mask &= ~boundmask; /* We can assume that we have array for the binding */ assert(attrmask); + + if (UPDATE == UPDATE_BUFFERS_ONLY) + continue; + /* Walk attributes belonging to the binding */ do { const gl_vert_attrib attr = (gl_vert_attrib)u_bit_scan(&attrmask); @@ -177,11 +189,11 @@ st_setup_arrays(struct st_context *st, { struct gl_context *ctx = st->ctx; - setup_arrays(st, ctx->Array._DrawVAO, vp->Base.Base.DualSlotInputs, - vp_variant->vert_attrib_mask, - _mesa_draw_nonzero_divisor_bits(ctx), - _mesa_draw_array_bits(ctx), _mesa_draw_user_array_bits(ctx), - velements, vbuffer, num_vbuffers, has_user_vertex_buffers); + setup_arrays + (st, ctx->Array._DrawVAO, vp->Base.Base.DualSlotInputs, + vp_variant->vert_attrib_mask, _mesa_draw_nonzero_divisor_bits(ctx), + _mesa_draw_array_bits(ctx), _mesa_draw_user_array_bits(ctx), + velements, vbuffer, num_vbuffers, has_user_vertex_buffers); } /* ALWAYS_INLINE helps the compiler realize that most of the parameters are @@ -190,7 +202,7 @@ st_setup_arrays(struct st_context *st, * Return the index of the vertex buffer where current attribs have been * uploaded. */ -template static void ALWAYS_INLINE +template void ALWAYS_INLINE st_setup_current(struct st_context *st, const struct st_vertex_program *vp, const struct st_common_variant *vp_variant, @@ -221,9 +233,11 @@ st_setup_current(struct st_context *st, if (alignment != size) memset(cursor + size, 0, alignment - size); - init_velement(velements->velems, &attrib->Format, cursor - data, - 0, bufidx, dual_slot_inputs & BITFIELD_BIT(attr), - util_bitcount_fast(inputs_read & BITFIELD_MASK(attr))); + if (UPDATE == UPDATE_ALL) { + init_velement(velements->velems, &attrib->Format, cursor - data, + 0, bufidx, dual_slot_inputs & BITFIELD_BIT(attr), + util_bitcount_fast(inputs_read & BITFIELD_MASK(attr))); + } cursor += alignment; } while (curmask); @@ -283,10 +297,11 @@ st_setup_current_user(struct st_context *st, } } -template inline void +template void ALWAYS_INLINE st_update_array_templ(struct st_context *st) { struct gl_context *ctx = st->ctx; + /* vertex program validation must be done before this */ /* _NEW_PROGRAM, ST_NEW_VS_STATE */ const struct st_vertex_program *vp = (struct st_vertex_program *)st->vp; @@ -299,44 +314,74 @@ st_update_array_templ(struct st_context *st) /* ST_NEW_VERTEX_ARRAYS alias ctx->DriverFlags.NewArray */ /* Setup arrays */ - setup_arrays(st, ctx->Array._DrawVAO, vp->Base.Base.DualSlotInputs, - vp_variant->vert_attrib_mask, - _mesa_draw_nonzero_divisor_bits(ctx), - _mesa_draw_array_bits(ctx), - _mesa_draw_user_array_bits(ctx), &velements, vbuffer, - &num_vbuffers, &uses_user_vertex_buffers); + setup_arrays + (st, ctx->Array._DrawVAO, vp->Base.Base.DualSlotInputs, + vp_variant->vert_attrib_mask, _mesa_draw_nonzero_divisor_bits(ctx), + _mesa_draw_array_bits(ctx), _mesa_draw_user_array_bits(ctx), + &velements, vbuffer, &num_vbuffers, &uses_user_vertex_buffers); /* _NEW_CURRENT_ATTRIB */ /* Setup zero-stride attribs. */ - st_setup_current(st, vp, vp_variant, &velements, vbuffer, - &num_vbuffers); + st_setup_current(st, vp, vp_variant, &velements, vbuffer, + &num_vbuffers); - velements.count = vp->num_inputs + vp_variant->key.passthrough_edgeflags; - - /* Set vertex buffers and elements. */ - struct cso_context *cso = st->cso_context; unsigned unbind_trailing_vbuffers = st->last_num_vbuffers > num_vbuffers ? st->last_num_vbuffers - num_vbuffers : 0; - cso_set_vertex_buffers_and_elements(cso, &velements, - num_vbuffers, - unbind_trailing_vbuffers, - true, - uses_user_vertex_buffers, - vbuffer); st->last_num_vbuffers = num_vbuffers; + + struct cso_context *cso = st->cso_context; + + if (UPDATE == UPDATE_ALL) { + velements.count = vp->num_inputs + vp_variant->key.passthrough_edgeflags; + + /* Set vertex buffers and elements. */ + cso_set_vertex_buffers_and_elements(cso, &velements, + num_vbuffers, + unbind_trailing_vbuffers, + true, + uses_user_vertex_buffers, + vbuffer); + /* The driver should clear this after it has processed the update. */ + ctx->Array.NewVertexElements = false; + st->uses_user_vertex_buffers = uses_user_vertex_buffers; + } else { + /* Only vertex buffers. */ + cso_set_vertex_buffers(cso, 0, num_vbuffers, unbind_trailing_vbuffers, + true, vbuffer); + /* This can change only when we update vertex elements. */ + assert(st->uses_user_vertex_buffers == uses_user_vertex_buffers); + } +} + +template void ALWAYS_INLINE +st_update_array_impl(struct st_context *st) +{ + struct gl_context *ctx = st->ctx; + + /* Changing from user to non-user buffers and vice versa can switch between + * cso and u_vbuf, which means that we need to update vertex elements even + * when they have not changed. + */ + if (ctx->Array.NewVertexElements || + st->uses_user_vertex_buffers != + !!(st->vp_variant->vert_attrib_mask & _mesa_draw_user_array_bits(ctx))) { + st_update_array_templ(st); + } else { + st_update_array_templ(st); + } } void st_update_array(struct st_context *st) { - st_update_array_templ(st); + st_update_array_impl(st); } void st_update_array_with_popcnt(struct st_context *st) { - st_update_array_templ(st); + st_update_array_impl(st); } struct pipe_vertex_state * @@ -353,9 +398,9 @@ st_create_gallium_vertex_state(struct gl_context *ctx, struct cso_velems_state velements; bool uses_user_vertex_buffers; - setup_arrays(st, vao, dual_slot_inputs, inputs_read, 0, - inputs_read, 0, &velements, vbuffer, &num_vbuffers, - &uses_user_vertex_buffers); + setup_arrays(st, vao, dual_slot_inputs, inputs_read, 0, + inputs_read, 0, &velements, vbuffer, &num_vbuffers, + &uses_user_vertex_buffers); if (num_vbuffers != 1 || uses_user_vertex_buffers) { assert(!"this should never happen with display lists"); diff --git a/src/mesa/state_tracker/st_cb_bitmap.c b/src/mesa/state_tracker/st_cb_bitmap.c index 0683ccd0c68..f538c081fae 100644 --- a/src/mesa/state_tracker/st_cb_bitmap.c +++ b/src/mesa/state_tracker/st_cb_bitmap.c @@ -280,6 +280,7 @@ restore_render_state(struct gl_context *ctx) cso_restore_state(cso, CSO_UNBIND_FS_SAMPLERVIEWS); st->state.num_sampler_views[PIPE_SHADER_FRAGMENT] = 0; + ctx->Array.NewVertexElements = true; st->dirty |= ST_NEW_VERTEX_ARRAYS | ST_NEW_FS_SAMPLER_VIEWS; } diff --git a/src/mesa/state_tracker/st_cb_clear.c b/src/mesa/state_tracker/st_cb_clear.c index 414e61be0ba..623c4355a91 100644 --- a/src/mesa/state_tracker/st_cb_clear.c +++ b/src/mesa/state_tracker/st_cb_clear.c @@ -361,6 +361,7 @@ clear_with_quad(struct gl_context *ctx, unsigned clear_buffers) /* Restore pipe state */ cso_restore_state(cso, 0); + ctx->Array.NewVertexElements = true; st->dirty |= ST_NEW_VERTEX_ARRAYS; } diff --git a/src/mesa/state_tracker/st_cb_drawpixels.c b/src/mesa/state_tracker/st_cb_drawpixels.c index c7c8f94aab4..0c375cc4ea4 100644 --- a/src/mesa/state_tracker/st_cb_drawpixels.c +++ b/src/mesa/state_tracker/st_cb_drawpixels.c @@ -949,6 +949,7 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, cso_restore_state(cso, CSO_UNBIND_FS_SAMPLERVIEWS); st->state.num_sampler_views[PIPE_SHADER_FRAGMENT] = 0; + ctx->Array.NewVertexElements = true; st->dirty |= ST_NEW_VERTEX_ARRAYS | ST_NEW_FS_SAMPLER_VIEWS; } diff --git a/src/mesa/state_tracker/st_cb_drawtex.c b/src/mesa/state_tracker/st_cb_drawtex.c index 262ce39fbe1..2e4c7c6f603 100644 --- a/src/mesa/state_tracker/st_cb_drawtex.c +++ b/src/mesa/state_tracker/st_cb_drawtex.c @@ -349,6 +349,7 @@ st_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z, /* restore state */ cso_restore_state(cso, 0); + ctx->Array.NewVertexElements = true; st->dirty |= ST_NEW_VERTEX_ARRAYS; } diff --git a/src/mesa/state_tracker/st_cb_readpixels.c b/src/mesa/state_tracker/st_cb_readpixels.c index c8d7d9c7d63..aed41ce32a6 100644 --- a/src/mesa/state_tracker/st_cb_readpixels.c +++ b/src/mesa/state_tracker/st_cb_readpixels.c @@ -260,6 +260,7 @@ fail: cso_restore_state(cso, CSO_UNBIND_FS_SAMPLERVIEWS | CSO_UNBIND_FS_IMAGE0); st->state.num_sampler_views[PIPE_SHADER_FRAGMENT] = 0; + st->ctx->Array.NewVertexElements = true; st->dirty |= ST_NEW_FS_CONSTANTS | ST_NEW_FS_IMAGES | ST_NEW_FS_SAMPLER_VIEWS | diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c index 65ef65f1524..950a2242354 100644 --- a/src/mesa/state_tracker/st_cb_texture.c +++ b/src/mesa/state_tracker/st_cb_texture.c @@ -1661,6 +1661,7 @@ fail: cso_restore_state(cso, CSO_UNBIND_FS_SAMPLERVIEWS); st->state.num_sampler_views[PIPE_SHADER_FRAGMENT] = 0; + ctx->Array.NewVertexElements = true; st->dirty |= ST_NEW_VERTEX_ARRAYS | ST_NEW_FS_CONSTANTS | ST_NEW_FS_SAMPLER_VIEWS; @@ -1951,6 +1952,7 @@ fail: cso_restore_state(cso, CSO_UNBIND_FS_SAMPLERVIEWS | CSO_UNBIND_FS_IMAGE0); st->state.num_sampler_views[PIPE_SHADER_FRAGMENT] = 0; + st->ctx->Array.NewVertexElements = true; st->dirty |= ST_NEW_FS_CONSTANTS | ST_NEW_FS_IMAGES | ST_NEW_FS_SAMPLER_VIEWS | diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c index ab2cc9642f9..919953baf64 100644 --- a/src/mesa/state_tracker/st_context.c +++ b/src/mesa/state_tracker/st_context.c @@ -241,8 +241,11 @@ st_invalidate_state(struct gl_context *ctx) if (new_state & _NEW_PIXEL) st->dirty |= ST_NEW_PIXEL_TRANSFER; - if (new_state & _NEW_CURRENT_ATTRIB && st_vp_uses_current_values(ctx)) + if (new_state & _NEW_CURRENT_ATTRIB && st_vp_uses_current_values(ctx)) { st->dirty |= ST_NEW_VERTEX_ARRAYS; + /* glColor3f -> glColor4f changes the vertex format. */ + ctx->Array.NewVertexElements = true; + } if (st->clamp_frag_depth_in_shader && (new_state & _NEW_VIEWPORT)) { if (ctx->GeometryProgram._Current) diff --git a/src/mesa/state_tracker/st_context.h b/src/mesa/state_tracker/st_context.h index 58bc8112429..f79c7506cf9 100644 --- a/src/mesa/state_tracker/st_context.h +++ b/src/mesa/state_tracker/st_context.h @@ -345,6 +345,7 @@ struct st_context /* The number of vertex buffers from the last call of validate_arrays. */ unsigned last_num_vbuffers; + bool uses_user_vertex_buffers; unsigned last_used_atomic_bindings[PIPE_SHADER_TYPES]; unsigned last_num_ssbos[PIPE_SHADER_TYPES]; diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c index e9cf42efcb5..10107153d5b 100644 --- a/src/mesa/state_tracker/st_draw.c +++ b/src/mesa/state_tracker/st_draw.c @@ -362,8 +362,10 @@ st_draw_gallium_vertex_state(struct gl_context *ctx, * just flag ST_NEW_VERTEX_ARRAY, which will also completely revalidate * edge flags in st_validate_state. */ - if (st->vertdata_edgeflags != old_vertdata_edgeflags) + if (st->vertdata_edgeflags != old_vertdata_edgeflags) { + ctx->Array.NewVertexElements = true; st->dirty |= ST_NEW_VERTEX_ARRAYS; + } } void diff --git a/src/mesa/state_tracker/st_manager.c b/src/mesa/state_tracker/st_manager.c index 9e0f29a2ccd..aed501e3705 100644 --- a/src/mesa/state_tracker/st_manager.c +++ b/src/mesa/state_tracker/st_manager.c @@ -847,8 +847,10 @@ st_context_invalidate_state(struct st_context_iface *stctxi, st->dirty |= ST_NEW_FS_CONSTANTS; if (flags & ST_INVALIDATE_VS_CONSTBUF0) st->dirty |= ST_NEW_VS_CONSTANTS; - if (flags & ST_INVALIDATE_VERTEX_BUFFERS) + if (flags & ST_INVALIDATE_VERTEX_BUFFERS) { + st->ctx->Array.NewVertexElements = true; st->dirty |= ST_NEW_VERTEX_ARRAYS; + } } diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c index 349f80c5be3..ece98763bb8 100644 --- a/src/mesa/state_tracker/st_program.c +++ b/src/mesa/state_tracker/st_program.c @@ -2022,10 +2022,12 @@ void st_finalize_program(struct st_context *st, struct gl_program *prog) { if (st->current_program[prog->info.stage] == prog) { - if (prog->info.stage == MESA_SHADER_VERTEX) + if (prog->info.stage == MESA_SHADER_VERTEX) { + st->ctx->Array.NewVertexElements = true; st->dirty |= ST_NEW_VERTEX_PROGRAM(st, (struct st_program *)prog); - else + } else { st->dirty |= ((struct st_program *)prog)->affected_states; + } } if (prog->nir) {