From 56e89c9e4fb00b5c2af4536d4c50294608d0c46c Mon Sep 17 00:00:00 2001 From: Radosław Kujawa Date: Sun, 2 Aug 2026 22:04:06 +0200 Subject: Performance improvements, support userspace simulators --- src/mesa/tnl/t_context.c | 9 ++- src/mesa/tnl/t_context.h | 3 + src/mesa/tnl/t_vb_light.c | 9 ++- src/mesa/tnl/t_vb_program.c | 5 +- src/mesa/tnl/t_vertex.c | 109 ++++++++++++++++++++++++++++++++--- src/mesa/tnl/t_vtx_api.c | 33 +++++++++-- src/mesa/tnl/t_vtx_api.h | 2 + src/mesa/tnl/t_vtx_generic.c | 133 ++++++++++++++++++++++++++----------------- 8 files changed, 234 insertions(+), 69 deletions(-) (limited to 'src/mesa/tnl') diff --git a/src/mesa/tnl/t_context.c b/src/mesa/tnl/t_context.c index e4d0d04..8db1c78 100644 --- a/src/mesa/tnl/t_context.c +++ b/src/mesa/tnl/t_context.c @@ -54,6 +54,13 @@ _tnl_MakeCurrent( GLcontext *ctx, (void) ctx; (void) drawBuffer; (void) readBuffer; } +static void +_tnl_validate_material( GLcontext *ctx ) +{ + _mesa_update_material( ctx, ~0 ); + _mesa_validate_all_lighting_tables( ctx ); +} + static void install_driver_callbacks( GLcontext *ctx ) @@ -123,7 +130,7 @@ _tnl_CreateContext( GLcontext *ctx ) tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts; tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts; - tnl->Driver.NotifyMaterialChange = _mesa_validate_all_lighting_tables; + tnl->Driver.NotifyMaterialChange = _tnl_validate_material; return GL_TRUE; } diff --git a/src/mesa/tnl/t_context.h b/src/mesa/tnl/t_context.h index 55b405e..ae565fb 100644 --- a/src/mesa/tnl/t_context.h +++ b/src/mesa/tnl/t_context.h @@ -278,6 +278,9 @@ struct _tnl_dynfn_generators { struct tnl_vtx { GLfloat buffer[VERT_BUFFER_SIZE]; GLubyte attrsz[_TNL_ATTRIB_MAX]; + GLubyte active_sz[_TNL_ATTRIB_MAX]; /* size the generic entrypoints + * currently store per attribute; + * 0 forces _tnl_choose_attr() */ GLuint vertex_size; struct tnl_prim prim[TNL_MAX_PRIM]; GLuint prim_count; diff --git a/src/mesa/tnl/t_vb_light.c b/src/mesa/tnl/t_vb_light.c index 1a89bf3..7d19c15 100644 --- a/src/mesa/tnl/t_vb_light.c +++ b/src/mesa/tnl/t_vb_light.c @@ -118,12 +118,11 @@ static GLuint prepare_materials( GLcontext *ctx, store->mat_bitmask |= (1<mat_count) { + _mesa_update_material( ctx, ~0 ); + _mesa_validate_all_lighting_tables( ctx ); + } return store->mat_count; } diff --git a/src/mesa/tnl/t_vb_program.c b/src/mesa/tnl/t_vb_program.c index 38b04b4..aedfb4e 100644 --- a/src/mesa/tnl/t_vb_program.c +++ b/src/mesa/tnl/t_vb_program.c @@ -355,7 +355,10 @@ static void dtr( struct tnl_pipeline_stage *stage ) const struct tnl_pipeline_stage _tnl_vertex_program_stage = { "vertex-program", - _NEW_ALL, /*XXX FIX */ /* recheck */ + _NEW_PROGRAM, /* recheck: check_vp() only reads + * VertexProgram._Enabled and + * Current->InputsRead, both always + * flushed with _NEW_PROGRAM */ _NEW_ALL, /*XXX FIX */ /* recalc */ GL_FALSE, /* active */ 0, /* inputs - calculated on the fly */ diff --git a/src/mesa/tnl/t_vertex.c b/src/mesa/tnl/t_vertex.c index 900648a..6245f70 100644 --- a/src/mesa/tnl/t_vertex.c +++ b/src/mesa/tnl/t_vertex.c @@ -871,6 +871,107 @@ static void generic_emit( GLcontext *ctx, } +#define FUSED_EMIT( NAME, COLSZ, HAVE_TEX ) \ +static void NAME( GLcontext *ctx, GLuint start, GLuint end, \ + void *dest ) \ +{ \ + struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); \ + const struct tnl_clipspace_attr *a = vtx->attr; \ + const GLfloat * const vp = a[0].vp; \ + const GLubyte *pos_ptr = a[0].inputptr; \ + const GLubyte *col_ptr = a[1].inputptr; \ + const GLubyte *tex_ptr = HAVE_TEX ? a[2].inputptr : NULL; \ + const GLuint pos_stride = a[0].inputstride; \ + const GLuint col_stride = a[1].inputstride; \ + const GLuint tex_stride = HAVE_TEX ? a[2].inputstride : 0; \ + const GLuint pos_off = a[0].vertoffset; \ + const GLuint col_off = a[1].vertoffset; \ + const GLuint tex_off = HAVE_TEX ? a[2].vertoffset : 0; \ + const GLuint stride = vtx->vertex_size; \ + GLubyte *v = (GLubyte *)dest; \ + GLuint i; \ + \ + end -= start; \ + \ + for (i = 0; i < end; i++, v += stride) { \ + { \ + const GLfloat *in = (const GLfloat *)pos_ptr; \ + GLfloat *out = (GLfloat *)(v + pos_off); \ + \ + out[0] = vp[0] * in[0] + vp[12]; \ + out[1] = vp[5] * in[1] + vp[13]; \ + out[2] = vp[10] * in[2] + vp[14]; \ + out[3] = in[3]; \ + pos_ptr += pos_stride; \ + } \ + { \ + const GLfloat *in = (const GLfloat *)col_ptr; \ + GLchan *c = (GLchan *)(v + col_off); \ + \ + UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]); \ + UNCLAMPED_FLOAT_TO_CHAN(c[1], in[1]); \ + UNCLAMPED_FLOAT_TO_CHAN(c[2], in[2]); \ + if (COLSZ == 4) { \ + UNCLAMPED_FLOAT_TO_CHAN(c[3], in[3]); \ + } \ + else \ + c[3] = CHAN_MAX; \ + col_ptr += col_stride; \ + } \ + if (HAVE_TEX) { \ + const GLfloat *in = (const GLfloat *)tex_ptr; \ + GLfloat *out = (GLfloat *)(v + tex_off); \ + \ + out[0] = in[0]; \ + out[1] = in[1]; \ + out[2] = 0; \ + out[3] = 1; \ + tex_ptr += tex_stride; \ + } \ + } \ +} + +FUSED_EMIT( emit_viewport4_rgba3, 3, 0 ) +FUSED_EMIT( emit_viewport4_rgba4, 4, 0 ) +FUSED_EMIT( emit_viewport4_rgba3_st, 3, 1 ) +FUSED_EMIT( emit_viewport4_rgba4_st, 4, 1 ) + +#undef FUSED_EMIT + +/* Match the installed attribute map plus this flush's input vector + * sizes against the fused layouts above; anything else takes + * generic_emit. + */ +static tnl_emit_func choose_emit_func( struct tnl_clipspace *vtx, + struct vertex_buffer *VB ) +{ + const struct tnl_clipspace_attr *a = vtx->attr; + const GLuint count = vtx->attr_count; + GLuint colsz; + + if (count < 2 || count > 3 || + a[0].format != EMIT_4F_VIEWPORT || + VB->AttribPtr[a[0].attrib]->size != 4 || + a[1].attrib != VERT_ATTRIB_COLOR0 || + a[1].format != EMIT_4CHAN_4F_RGBA) + return generic_emit; + + colsz = VB->AttribPtr[a[1].attrib]->size; + if (colsz != 3 && colsz != 4) + return generic_emit; + + if (count == 3) { + if (a[2].format != EMIT_4F || + VB->AttribPtr[a[2].attrib]->size != 2) + return generic_emit; + return (colsz == 4) ? emit_viewport4_rgba4_st + : emit_viewport4_rgba3_st; + } + + return (colsz == 4) ? emit_viewport4_rgba4 : emit_viewport4_rgba3; +} + + static void generic_interp( GLcontext *ctx, GLfloat t, GLuint edst, GLuint eout, GLuint ein, @@ -1030,13 +1131,7 @@ static void do_emit( GLcontext *ctx, GLuint start, GLuint end, a[j].emit = a[j].insert[vptr->size - 1]; } - vtx->emit = 0; - - if (0) - vtx->emit = _tnl_codegen_emit(ctx); - - if (!vtx->emit) - vtx->emit = generic_emit; + vtx->emit = choose_emit_func( vtx, VB ); vtx->emit( ctx, start, end, dest ); } diff --git a/src/mesa/tnl/t_vtx_api.c b/src/mesa/tnl/t_vtx_api.c index 56b1e9f..f2e7857 100644 --- a/src/mesa/tnl/t_vtx_api.c +++ b/src/mesa/tnl/t_vtx_api.c @@ -312,14 +312,20 @@ static void _tnl_wrap_upgrade_vertex( GLcontext *ctx, * codegen. Might be a reasonable place to try & detect attributes * in the vertex which aren't being submitted any more. */ - for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++) + for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++) { + /* Force the generic entrypoints through _tnl_choose_attr() again + * so shrunken attributes get their identity components refilled + * (mirrors the tabfv reset below). + */ + tnl->vtx.active_sz[i] = 0; + if (tnl->vtx.attrsz[i]) { GLuint j = tnl->vtx.attrsz[i] - 1; if (i < _TNL_MAX_ATTR_CODEGEN) tnl->vtx.tabfv[i][j] = choose[i][j]; } - + } } @@ -440,6 +446,22 @@ static tnl_attrfv_func do_choose( GLuint attr, GLuint sz ) +/* Helper for the single-dispatch generic entrypoints + */ +void _tnl_choose_attr( GLcontext *ctx, GLuint attr, GLuint sz ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + + assert(attr < _TNL_ATTRIB_MAX); + assert(sz >= 1 && sz <= 4); + + if (tnl->vtx.attrsz[attr] != sz) + _tnl_fixup_vertex( ctx, attr, sz ); + + tnl->vtx.active_sz[attr] = (GLubyte) sz; +} + + #define CHOOSE( ATTR, N ) \ static void choose_##ATTR##_##N( const GLfloat *v ) \ { \ @@ -487,10 +509,12 @@ static void error_attrib( const GLfloat *unused ) static void reset_attrfv( TNLcontext *tnl ) -{ +{ GLuint i; - for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++) + for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++) { + tnl->vtx.active_sz[i] = 0; + if (tnl->vtx.attrsz[i]) { GLint j = tnl->vtx.attrsz[i] - 1; tnl->vtx.attrsz[i] = 0; @@ -502,6 +526,7 @@ static void reset_attrfv( TNLcontext *tnl ) } } } + } tnl->vtx.vertex_size = 0; tnl->vtx.have_materials = 0; diff --git a/src/mesa/tnl/t_vtx_api.h b/src/mesa/tnl/t_vtx_api.h index 9818c08..0480bad 100644 --- a/src/mesa/tnl/t_vtx_api.h +++ b/src/mesa/tnl/t_vtx_api.h @@ -51,6 +51,8 @@ extern void _tnl_flush_vtx( GLcontext *ctx ); extern void GLAPIENTRY _tnl_wrap_filled_vertex( GLcontext *ctx ); +extern void _tnl_choose_attr( GLcontext *ctx, GLuint attr, GLuint sz ); + /* t_vtx_exec.c: */ diff --git a/src/mesa/tnl/t_vtx_generic.c b/src/mesa/tnl/t_vtx_generic.c index daa7dea..faf7e19 100644 --- a/src/mesa/tnl/t_vtx_generic.c +++ b/src/mesa/tnl/t_vtx_generic.c @@ -133,52 +133,51 @@ void _tnl_generic_attr_table_init( tnl_attrfv_func (*tab)[4] ) INIT( tab, 15 ); } -/* These can be made efficient with codegen. Further, by adding more - * logic to do_choose(), the double-dispatch for legacy entrypoints - * like glVertex3f() can be removed. - */ -#define DISPATCH_ATTRFV( ATTR, COUNT, P ) \ -do { \ - GET_CURRENT_CONTEXT( ctx ); \ - TNLcontext *tnl = TNL_CONTEXT(ctx); \ - tnl->vtx.tabfv[ATTR][COUNT-1]( P ); \ +/* Single-dispatch entrypoints */ +#define ATTRF( A, N, X, Y, Z, W ) \ +do { \ + GET_CURRENT_CONTEXT( ctx ); \ + TNLcontext *tnl = TNL_CONTEXT(ctx); \ + \ + if (tnl->vtx.active_sz[A] != (N)) \ + _tnl_choose_attr( ctx, (A), (N) ); \ + \ + if ((A) == 0) { \ + GLfloat *dest = tnl->vtx.vbptr; \ + GLuint i; \ + \ + if ((N)>0) dest[0] = (X); \ + if ((N)>1) dest[1] = (Y); \ + if ((N)>2) dest[2] = (Z); \ + if ((N)>3) dest[3] = (W); \ + \ + for (i = (N); i < tnl->vtx.vertex_size; i++) \ + dest[i] = tnl->vtx.vertex[i]; \ + \ + tnl->vtx.vbptr = dest + tnl->vtx.vertex_size; \ + \ + if (--tnl->vtx.counter == 0) \ + _tnl_wrap_filled_vertex( ctx ); \ + } \ + else { \ + GLfloat *dest = tnl->vtx.attrptr[A]; \ + \ + if ((N)>0) dest[0] = (X); \ + if ((N)>1) dest[1] = (Y); \ + if ((N)>2) dest[2] = (Z); \ + if ((N)>3) dest[3] = (W); \ + } \ } while (0) -#define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V ) -#define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V ) -#define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V ) -#define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V ) - -#define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) ) +#define DISPATCH_ATTR1FV( ATTR, V ) ATTRF( ATTR, 1, (V)[0], 0, 0, 1 ) +#define DISPATCH_ATTR2FV( ATTR, V ) ATTRF( ATTR, 2, (V)[0], (V)[1], 0, 1 ) +#define DISPATCH_ATTR3FV( ATTR, V ) ATTRF( ATTR, 3, (V)[0], (V)[1], (V)[2], 1 ) +#define DISPATCH_ATTR4FV( ATTR, V ) ATTRF( ATTR, 4, (V)[0], (V)[1], (V)[2], (V)[3] ) -#if defined(USE_X86_ASM) && 0 /* will break register calling convention */ -/* Naughty cheat: - */ -#define DISPATCH_ATTR2F( ATTR, S,T ) DISPATCH_ATTRFV( ATTR, 2, &(S) ) -#define DISPATCH_ATTR3F( ATTR, S,T,R ) DISPATCH_ATTRFV( ATTR, 3, &(S) ) -#define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) DISPATCH_ATTRFV( ATTR, 4, &(S) ) -#else -/* Safe: - */ -#define DISPATCH_ATTR2F( ATTR, S,T ) \ -do { \ - GLfloat v[2]; \ - v[0] = S; v[1] = T; \ - DISPATCH_ATTR2FV( ATTR, v ); \ -} while (0) -#define DISPATCH_ATTR3F( ATTR, S,T,R ) \ -do { \ - GLfloat v[3]; \ - v[0] = S; v[1] = T; v[2] = R; \ - DISPATCH_ATTR3FV( ATTR, v ); \ -} while (0) -#define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \ -do { \ - GLfloat v[4]; \ - v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \ - DISPATCH_ATTR4FV( ATTR, v ); \ -} while (0) -#endif +#define DISPATCH_ATTR1F( ATTR, S ) ATTRF( ATTR, 1, S, 0, 0, 1 ) +#define DISPATCH_ATTR2F( ATTR, S,T ) ATTRF( ATTR, 2, S, T, 0, 1 ) +#define DISPATCH_ATTR3F( ATTR, S,T,R ) ATTRF( ATTR, 3, S, T, R, 1 ) +#define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) ATTRF( ATTR, 4, S, T, R, Q ) static void GLAPIENTRY _tnl_Vertex2f( GLfloat x, GLfloat y ) @@ -363,42 +362,66 @@ static void GLAPIENTRY _tnl_MultiTexCoord4fv( GLenum target, static void GLAPIENTRY _tnl_VertexAttrib1fNV( GLuint index, GLfloat x ) { - if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB; + if (index >= VERT_ATTRIB_MAX) { + GET_CURRENT_CONTEXT( ctx ); + _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" ); + return; + } DISPATCH_ATTR1F( index, x ); } static void GLAPIENTRY _tnl_VertexAttrib1fvNV( GLuint index, const GLfloat *v ) { - if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB; + if (index >= VERT_ATTRIB_MAX) { + GET_CURRENT_CONTEXT( ctx ); + _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" ); + return; + } DISPATCH_ATTR1FV( index, v ); } static void GLAPIENTRY _tnl_VertexAttrib2fNV( GLuint index, GLfloat x, GLfloat y ) { - if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB; + if (index >= VERT_ATTRIB_MAX) { + GET_CURRENT_CONTEXT( ctx ); + _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" ); + return; + } DISPATCH_ATTR2F( index, x, y ); } static void GLAPIENTRY _tnl_VertexAttrib2fvNV( GLuint index, const GLfloat *v ) { - if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB; + if (index >= VERT_ATTRIB_MAX) { + GET_CURRENT_CONTEXT( ctx ); + _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" ); + return; + } DISPATCH_ATTR2FV( index, v ); } static void GLAPIENTRY _tnl_VertexAttrib3fNV( GLuint index, GLfloat x, GLfloat y, GLfloat z ) { - if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB; + if (index >= VERT_ATTRIB_MAX) { + GET_CURRENT_CONTEXT( ctx ); + _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" ); + return; + } DISPATCH_ATTR3F( index, x, y, z ); } static void GLAPIENTRY _tnl_VertexAttrib3fvNV( GLuint index, const GLfloat *v ) { - if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB; + if (index >= VERT_ATTRIB_MAX) { + GET_CURRENT_CONTEXT( ctx ); + _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" ); + return; + } DISPATCH_ATTR3FV( index, v ); } @@ -406,14 +429,22 @@ static void GLAPIENTRY _tnl_VertexAttrib4fNV( GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w ) { - if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB; + if (index >= VERT_ATTRIB_MAX) { + GET_CURRENT_CONTEXT( ctx ); + _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" ); + return; + } DISPATCH_ATTR4F( index, x, y, z, w ); } static void GLAPIENTRY _tnl_VertexAttrib4fvNV( GLuint index, const GLfloat *v ) { - if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB; + if (index >= VERT_ATTRIB_MAX) { + GET_CURRENT_CONTEXT( ctx ); + _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" ); + return; + } DISPATCH_ATTR4FV( index, v ); } -- cgit