aboutsummaryrefslogtreecommitdiff
path: root/src/mesa/tnl
diff options
context:
space:
mode:
authorRadosław Kujawa <radoslaw.kujawa@c0ff33.net>2026-08-02 22:04:06 +0200
committerRadosław Kujawa <radoslaw.kujawa@c0ff33.net>2026-08-02 22:04:32 +0200
commit56e89c9e4fb00b5c2af4536d4c50294608d0c46c (patch)
treeb247c62b317ce11e8c26e5b311a16cfae2f7d9c9 /src/mesa/tnl
parentafc74a01283fad7dfbbd670a535e68d90de7ed9a (diff)
Performance improvements, support userspace simulatorsHEADmaster
Diffstat (limited to 'src/mesa/tnl')
-rw-r--r--src/mesa/tnl/t_context.c9
-rw-r--r--src/mesa/tnl/t_context.h3
-rw-r--r--src/mesa/tnl/t_vb_light.c9
-rw-r--r--src/mesa/tnl/t_vb_program.c5
-rw-r--r--src/mesa/tnl/t_vertex.c109
-rw-r--r--src/mesa/tnl/t_vtx_api.c33
-rw-r--r--src/mesa/tnl/t_vtx_api.h2
-rw-r--r--src/mesa/tnl/t_vtx_generic.c133
8 files changed, 234 insertions, 69 deletions
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<<attr);
}
}
-
- /* FIXME: Is this already done?
- */
- _mesa_update_material( ctx, ~0 );
- _mesa_validate_all_lighting_tables( ctx );
+ if (store->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 );
}