2 /**************************************************************************
4 Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
8 Permission is hereby granted, free of charge, to any person obtaining a
9 copy of this software and associated documentation files (the "Software"),
10 to deal in the Software without restriction, including without limitation
11 on the rights to use, copy, modify, merge, publish, distribute, sub
12 license, and/or sell copies of the Software, and to permit persons to whom
13 the Software is furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice (including the next
16 paragraph) shall be included in all copies or substantial portions of the
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 USE OR OTHER DEALINGS IN THE SOFTWARE.
27 **************************************************************************/
31 * Keith Whitwell <keith@tungstengraphics.com>
35 #include "api_arrayelt.h"
48 #include "tnl/t_context.h"
49 #include "tnl/t_array_api.h"
51 static void _tnl_FlushVertices( GLcontext
*, GLuint
);
54 void tnl_copy_to_current( GLcontext
*ctx
)
56 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
57 GLuint flag
= tnl
->vertex_format
;
60 assert(ctx
->Driver
.NeedFlush
& FLUSH_UPDATE_CURRENT
);
62 for (i
= 0 ; i
< 16 ; i
++)
64 COPY_4FV( ctx
->Current
.Attrib
[i
], tnl
->attribptr
[i
] );
66 if (flag
& VERT_BIT_INDEX
)
67 ctx
->Current
.Index
= tnl
->indexptr
[0];
69 if (flag
& VERT_BIT_EDGEFLAG
)
70 ctx
->Current
.EdgeFlag
= tnl
->edgeflagptr
[0];
72 if (flag
& VERT_BIT_MATERIAL
) {
73 _mesa_update_material( ctx
,
74 IM
->Material
[IM
->LastMaterial
],
77 tnl
->Driver
.NotifyMaterialChange( ctx
);
81 ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
84 static GLboolean discreet_gl_prim
[GL_POLYGON
+1] = {
97 /* Optimize the primitive list: ONLY FOR EXECUTE ATM
99 static void optimize_prims( TNLcontext
*tnl
)
103 if (tnl
->nrprims
<= 1)
106 for (j
= 0, i
= 1 ; i
< tnl
->nrprims
; i
++) {
107 int pj
= tnl
->primlist
[j
].prim
& 0xf;
108 int pi
= tnl
->primlist
[i
].prim
& 0xf;
110 if (pj
== pi
&& discreet_gl_prim
[pj
] &&
111 tnl
->primlist
[i
].start
== tnl
->primlist
[j
].end
) {
112 tnl
->primlist
[j
].end
= tnl
->primlist
[i
].end
;
116 if (j
!= i
) tnl
->primlist
[j
] = tnl
->primlist
[i
];
124 /* Bind vertex buffer pointers, run pipeline:
126 static void flush_prims( TNLcontext
*tnl
)
130 tnl
->dma
.current
.ptr
= tnl
->dma
.current
.start
+=
131 (tnl
->initial_counter
- tnl
->counter
) * tnl
->vertex_size
* 4;
133 tnl
->tcl
.vertex_format
= tnl
->vertex_format
;
134 tnl
->tcl
.aos_components
[0] = &tmp
;
135 tnl
->tcl
.nr_aos_components
= 1;
138 tnl
->Driver
.RunPipeline( ... );
144 static void start_prim( TNLcontext
*tnl
, GLuint mode
)
146 if (MESA_VERBOSE
& DEBUG_VFMT
)
147 _mesa_debug(NULL
, "%s %d\n", __FUNCTION__
,
148 tnl
->initial_counter
- tnl
->counter
);
150 tnl
->primlist
[tnl
->nrprims
].start
= tnl
->initial_counter
- tnl
->counter
;
151 tnl
->primlist
[tnl
->nrprims
].prim
= mode
;
154 static void note_last_prim( TNLcontext
*tnl
, GLuint flags
)
156 if (MESA_VERBOSE
& DEBUG_VFMT
)
157 _mesa_debug(NULL
, "%s %d\n", __FUNCTION__
,
158 tnl
->initial_counter
- tnl
->counter
);
160 if (tnl
->prim
[0] != GL_POLYGON
+1) {
161 tnl
->primlist
[tnl
->nrprims
].prim
|= flags
;
162 tnl
->primlist
[tnl
->nrprims
].end
= tnl
->initial_counter
- tnl
->counter
;
164 if (++tnl
->nrprims
== TNL_MAX_PRIMS
)
170 static void copy_vertex( TNLcontext
*tnl
, GLuint n
, GLfloat
*dst
)
173 GLfloat
*src
= (GLfloat
*)(tnl
->dma
.current
.address
+
174 tnl
->dma
.current
.ptr
+
175 (tnl
->primlist
[tnl
->nrprims
].start
+ n
) *
176 tnl
->vertex_size
* 4);
178 if (MESA_VERBOSE
& DEBUG_VFMT
)
179 _mesa_debug(NULL
, "copy_vertex %d\n",
180 tnl
->primlist
[tnl
->nrprims
].start
+ n
);
182 for (i
= 0 ; i
< tnl
->vertex_size
; i
++) {
187 static GLuint
copy_wrapped_verts( TNLcontext
*tnl
, GLfloat (*tmp
)[15] )
190 GLuint nr
= (tnl
->initial_counter
- tnl
->counter
) - tnl
->primlist
[tnl
->nrprims
].start
;
192 if (MESA_VERBOSE
& DEBUG_VFMT
)
193 _mesa_debug(NULL
, "%s %d verts\n", __FUNCTION__
, nr
);
195 switch( tnl
->prim
[0] )
201 for (i
= 0 ; i
< ovf
; i
++)
202 copy_vertex( tnl
, nr
-ovf
+i
, tmp
[i
] );
206 for (i
= 0 ; i
< ovf
; i
++)
207 copy_vertex( tnl
, nr
-ovf
+i
, tmp
[i
] );
211 for (i
= 0 ; i
< ovf
; i
++)
212 copy_vertex( tnl
, nr
-ovf
+i
, tmp
[i
] );
217 copy_vertex( tnl
, nr
-1, tmp
[0] );
220 case GL_TRIANGLE_FAN
:
225 copy_vertex( tnl
, 0, tmp
[0] );
228 copy_vertex( tnl
, 0, tmp
[0] );
229 copy_vertex( tnl
, nr
-1, tmp
[1] );
232 case GL_TRIANGLE_STRIP
:
233 ovf
= MIN2( nr
-1, 2 );
234 for (i
= 0 ; i
< ovf
; i
++)
235 copy_vertex( tnl
, nr
-ovf
+i
, tmp
[i
] );
238 ovf
= MIN2( nr
-1, 2 );
239 if (nr
> 2) ovf
+= nr
&1;
240 for (i
= 0 ; i
< ovf
; i
++)
241 copy_vertex( tnl
, nr
-ovf
+i
, tmp
[i
] );
251 /* Extend for vertex-format changes on wrap:
253 static void wrap_buffer( void )
255 TNLcontext
*tnl
= tnl
->tnl
;
259 if (MESA_VERBOSE
& (DEBUG_VFMT
|DEBUG_PRIMS
))
260 _mesa_debug(NULL
, "%s %d\n", __FUNCTION__
,
261 tnl
->initial_counter
- tnl
->counter
);
263 /* Don't deal with parity. *** WONT WORK FOR COMPILE
265 if ((((tnl
->initial_counter
- tnl
->counter
) -
266 tnl
->primlist
[tnl
->nrprims
].start
) & 1)) {
268 tnl
->initial_counter
++;
272 /* Copy vertices out of dma:
274 nrverts
= copy_dma_verts( tnl
, tmp
);
276 if (MESA_VERBOSE
& DEBUG_VFMT
)
277 _mesa_debug(NULL
, "%d vertices to copy\n", nrverts
);
280 /* Finish the prim at this point:
282 note_last_prim( tnl
, 0 );
285 /* Reset counter, dmaptr
287 tnl
->dmaptr
= (int *)(tnl
->dma
.current
.ptr
+ tnl
->dma
.current
.address
);
288 tnl
->counter
= (tnl
->dma
.current
.end
- tnl
->dma
.current
.ptr
) /
289 (tnl
->vertex_size
* 4);
291 tnl
->initial_counter
= tnl
->counter
;
292 tnl
->notify
= wrap_buffer
;
294 tnl
->dma
.flush
= flush_prims
;
295 start_prim( tnl
, tnl
->prim
[0] );
298 /* Reemit saved vertices
299 * *** POSSIBLY IN NEW FORMAT
300 * --> Can't always extend at end of vertex?
302 for (i
= 0 ; i
< nrverts
; i
++) {
303 if (MESA_VERBOSE
& DEBUG_VERTS
) {
305 _mesa_debug(NULL
, "re-emit vertex %d to %p\n", i
, tnl
->dmaptr
);
306 if (MESA_VERBOSE
& DEBUG_VERBOSE
)
307 for (j
= 0 ; j
< tnl
->vertex_size
; j
++)
308 _mesa_debug(NULL
, "\t%08x/%f\n", *(int*)&tmp
[i
][j
], tmp
[i
][j
]);
311 memcpy( tnl
->dmaptr
, tmp
[i
], tnl
->vertex_size
* 4 );
312 tnl
->dmaptr
+= tnl
->vertex_size
;
319 /* Always follow data, don't try to predict what's necessary.
321 static GLboolean
check_vtx_fmt( GLcontext
*ctx
)
323 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
325 if (ctx
->Driver
.NeedFlush
& FLUSH_UPDATE_CURRENT
)
326 ctx
->Driver
.FlushVertices( ctx
, FLUSH_UPDATE_CURRENT
);
330 tnl
->vertex_format
= VERT_BIT_POS
;
331 tnl
->prim
= &ctx
->Driver
.CurrentExecPrimitive
;
334 /* Currently allow the full 4 components per attrib. Can use the
335 * mechanism from radeon driver color handling to reduce this (and
336 * also to store ubyte colors where these are incoming). This
337 * won't work for compile mode.
339 * Only adding components when they are first received eliminates
340 * the need for displaylist fixup, as there are no 'empty' slots
341 * at the start of buffers.
343 for (i
= 0 ; i
< 16 ; i
++) {
345 tnl
->attribptr
[i
] = &tnl
->vertex
[tnl
->vertex_size
].f
;
346 tnl
->vertex_size
+= 4;
347 tnl
->attribptr
[i
][0] = ctx
->Current
.Attrib
[i
][0];
348 tnl
->attribptr
[i
][1] = ctx
->Current
.Attrib
[i
][1];
349 tnl
->attribptr
[i
][2] = ctx
->Current
.Attrib
[i
][2];
350 tnl
->attribptr
[i
][3] = ctx
->Current
.Attrib
[i
][3];
353 tnl
->attribptr
[i
] = ctx
->Current
.Attrib
[i
];
358 for (i
= 16 ; i
< 18 ; i
++)
363 for (i
= 18 ; i
< 28 ; i
++)
368 for (i
= 28 ; i
< 29 ; i
++)
372 if (tnl
->installed_vertex_format
!= tnl
->vertex_format
) {
373 if (MESA_VERBOSE
& DEBUG_VFMT
)
374 _mesa_debug(NULL
, "reinstall on vertex_format change\n");
375 _mesa_install_exec_vtxfmt( ctx
, &tnl
->vtxfmt
);
376 tnl
->installed_vertex_format
= tnl
->vertex_format
;
383 void _tnl_InvalidateVtxfmt( GLcontext
*ctx
)
385 tnl
->recheck
= GL_TRUE
;
386 tnl
->fell_back
= GL_FALSE
;
392 static void _tnl_ValidateVtxfmt( GLcontext
*ctx
)
394 if (MESA_VERBOSE
& DEBUG_VFMT
)
395 _mesa_debug(NULL
, "%s\n", __FUNCTION__
);
397 if (ctx
->Driver
.NeedFlush
)
398 ctx
->Driver
.FlushVertices( ctx
, ctx
->Driver
.NeedFlush
);
400 tnl
->recheck
= GL_FALSE
;
402 if (check_vtx_fmt( ctx
)) {
403 if (!tnl
->installed
) {
404 if (MESA_VERBOSE
& DEBUG_VFMT
)
405 _mesa_debug(NULL
, "reinstall (new install)\n");
407 _mesa_install_exec_vtxfmt( ctx
, &tnl
->vtxfmt
);
408 ctx
->Driver
.FlushVertices
= _tnl_FlushVertices
;
409 tnl
->installed
= GL_TRUE
;
412 _mesa_debug(NULL
, "%s: already installed", __FUNCTION__
);
415 if (MESA_VERBOSE
& DEBUG_VFMT
)
416 _mesa_debug(NULL
, "%s: failed\n", __FUNCTION__
);
418 if (tnl
->installed
) {
419 if (tnl
->tnl
->dma
.flush
)
420 tnl
->tnl
->dma
.flush( tnl
->tnl
);
421 _tnl_wakeup_exec( ctx
);
422 tnl
->installed
= GL_FALSE
;
433 static void _tnl_Begin( GLenum mode
)
435 GLcontext
*ctx
= tnl
->context
;
436 TNLcontext
*tnl
= tnl
->tnl
;
438 if (MESA_VERBOSE
& DEBUG_VFMT
)
439 _mesa_debug(NULL
, "%s\n", __FUNCTION__
);
441 if (mode
> GL_POLYGON
) {
442 _mesa_error( ctx
, GL_INVALID_ENUM
, "glBegin" );
446 if (tnl
->prim
[0] != GL_POLYGON
+1) {
447 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
452 _mesa_update_state( ctx
);
455 _tnl_ValidateVtxfmt( ctx
);
457 if (tnl
->dma
.flush
&& tnl
->counter
< 12) {
458 if (MESA_VERBOSE
& DEBUG_VFMT
)
459 _mesa_debug(NULL
, "%s: flush almost-empty buffers\n", __FUNCTION__
);
463 if (!tnl
->dma
.flush
) {
464 if (tnl
->dma
.current
.ptr
+ 12*tnl
->vertex_size
*4 >
465 tnl
->dma
.current
.end
) {
467 _tnl_RefillCurrentDmaRegion( tnl
);
470 tnl
->dmaptr
= (int *)(tnl
->dma
.current
.address
+ tnl
->dma
.current
.ptr
);
471 tnl
->counter
= (tnl
->dma
.current
.end
- tnl
->dma
.current
.ptr
) /
472 (tnl
->vertex_size
* 4);
474 tnl
->initial_counter
= tnl
->counter
;
475 tnl
->notify
= wrap_buffer
;
476 tnl
->dma
.flush
= flush_prims
;
477 tnl
->context
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
482 start_prim( tnl
, mode
| PRIM_BEGIN
);
489 static void _tnl_End( void )
491 TNLcontext
*tnl
= tnl
->tnl
;
492 GLcontext
*ctx
= tnl
->context
;
494 if (MESA_VERBOSE
& DEBUG_VFMT
)
495 _mesa_debug(NULL
, "%s\n", __FUNCTION__
);
497 if (tnl
->prim
[0] == GL_POLYGON
+1) {
498 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
502 note_last_prim( tnl
, PRIM_END
);
503 tnl
->prim
[0] = GL_POLYGON
+1;
507 static void _tnl_FlushVertices( GLcontext
*ctx
, GLuint flags
)
509 if (MESA_VERBOSE
& DEBUG_VFMT
)
510 _mesa_debug(NULL
, "%s\n", __FUNCTION__
);
512 assert(tnl
->installed
);
514 if (flags
& FLUSH_UPDATE_CURRENT
) {
515 _tnl_copy_to_current( ctx
);
516 if (MESA_VERBOSE
& DEBUG_VFMT
)
517 _mesa_debug(NULL
, "reinstall on update_current\n");
518 _mesa_install_exec_vtxfmt( ctx
, &tnl
->vtxfmt
);
519 ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
522 if (flags
& FLUSH_STORED_VERTICES
) {
523 TNLcontext
*tnl
= TNL_CONTEXT( ctx
);
524 assert (tnl
->dma
.flush
== 0 ||
525 tnl
->dma
.flush
== flush_prims
);
526 if (tnl
->dma
.flush
== flush_prims
)
527 flush_prims( TNL_CONTEXT( ctx
) );
528 ctx
->Driver
.NeedFlush
&= ~FLUSH_STORED_VERTICES
;
534 /* At this point, don't expect very many versions of each function to
535 * be generated, so not concerned about freeing them?
539 static void _tnl_InitVtxfmt( GLcontext
*ctx
)
541 GLvertexformat
*vfmt
= &(tnl
->vtxfmt
);
543 MEMSET( vfmt
, 0, sizeof(GLvertexformat
) );
545 /* Hook in chooser functions for codegen, etc:
547 _tnl_InitVtxfmtChoosers( vfmt
);
549 /* Handled fully in supported states, but no codegen:
551 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
552 vfmt
->Rectf
= _mesa_noop_Rectf
; /* generic helper */
553 vfmt
->Begin
= _tnl_Begin
;
554 vfmt
->End
= _tnl_End
;
557 tnl
->tnl
= TNL_CONTEXT(ctx
);
558 tnl
->prim
= &ctx
->Driver
.CurrentExecPrimitive
;
561 make_empty_list( &tnl
->dfn_cache
.Vertex2f
);
562 make_empty_list( &tnl
->dfn_cache
.Vertex2fv
);
563 make_empty_list( &tnl
->dfn_cache
.Vertex3f
);
564 make_empty_list( &tnl
->dfn_cache
.Vertex3fv
);
565 make_empty_list( &tnl
->dfn_cache
.Color4ub
);
566 make_empty_list( &tnl
->dfn_cache
.Color4ubv
);
567 make_empty_list( &tnl
->dfn_cache
.Color3ub
);
568 make_empty_list( &tnl
->dfn_cache
.Color3ubv
);
569 make_empty_list( &tnl
->dfn_cache
.Color4f
);
570 make_empty_list( &tnl
->dfn_cache
.Color4fv
);
571 make_empty_list( &tnl
->dfn_cache
.Color3f
);
572 make_empty_list( &tnl
->dfn_cache
.Color3fv
);
573 make_empty_list( &tnl
->dfn_cache
.SecondaryColor3fEXT
);
574 make_empty_list( &tnl
->dfn_cache
.SecondaryColor3fvEXT
);
575 make_empty_list( &tnl
->dfn_cache
.SecondaryColor3ubEXT
);
576 make_empty_list( &tnl
->dfn_cache
.SecondaryColor3ubvEXT
);
577 make_empty_list( &tnl
->dfn_cache
.Normal3f
);
578 make_empty_list( &tnl
->dfn_cache
.Normal3fv
);
579 make_empty_list( &tnl
->dfn_cache
.TexCoord2f
);
580 make_empty_list( &tnl
->dfn_cache
.TexCoord2fv
);
581 make_empty_list( &tnl
->dfn_cache
.TexCoord1f
);
582 make_empty_list( &tnl
->dfn_cache
.TexCoord1fv
);
583 make_empty_list( &tnl
->dfn_cache
.MultiTexCoord2fARB
);
584 make_empty_list( &tnl
->dfn_cache
.MultiTexCoord2fvARB
);
585 make_empty_list( &tnl
->dfn_cache
.MultiTexCoord1fARB
);
586 make_empty_list( &tnl
->dfn_cache
.MultiTexCoord1fvARB
);
588 _tnl_InitCodegen( &tnl
->codegen
);
591 static void free_funcs( struct dynfn
*l
)
593 struct dynfn
*f
, *tmp
;
594 foreach_s (f
, tmp
, l
) {
595 remove_from_list( f
);
596 ALIGN_FREE( f
->code
);
602 static void _tnl_DestroyVtxfmt( GLcontext
*ctx
)
605 free_funcs( &tnl
->dfn_cache
.Vertex2f
);
606 free_funcs( &tnl
->dfn_cache
.Vertex2fv
);
607 free_funcs( &tnl
->dfn_cache
.Vertex3f
);
608 free_funcs( &tnl
->dfn_cache
.Vertex3fv
);
609 free_funcs( &tnl
->dfn_cache
.Color4ub
);
610 free_funcs( &tnl
->dfn_cache
.Color4ubv
);
611 free_funcs( &tnl
->dfn_cache
.Color3ub
);
612 free_funcs( &tnl
->dfn_cache
.Color3ubv
);
613 free_funcs( &tnl
->dfn_cache
.Color4f
);
614 free_funcs( &tnl
->dfn_cache
.Color4fv
);
615 free_funcs( &tnl
->dfn_cache
.Color3f
);
616 free_funcs( &tnl
->dfn_cache
.Color3fv
);
617 free_funcs( &tnl
->dfn_cache
.SecondaryColor3ubEXT
);
618 free_funcs( &tnl
->dfn_cache
.SecondaryColor3ubvEXT
);
619 free_funcs( &tnl
->dfn_cache
.SecondaryColor3fEXT
);
620 free_funcs( &tnl
->dfn_cache
.SecondaryColor3fvEXT
);
621 free_funcs( &tnl
->dfn_cache
.Normal3f
);
622 free_funcs( &tnl
->dfn_cache
.Normal3fv
);
623 free_funcs( &tnl
->dfn_cache
.TexCoord2f
);
624 free_funcs( &tnl
->dfn_cache
.TexCoord2fv
);
625 free_funcs( &tnl
->dfn_cache
.TexCoord1f
);
626 free_funcs( &tnl
->dfn_cache
.TexCoord1fv
);
627 free_funcs( &tnl
->dfn_cache
.MultiTexCoord2fARB
);
628 free_funcs( &tnl
->dfn_cache
.MultiTexCoord2fvARB
);
629 free_funcs( &tnl
->dfn_cache
.MultiTexCoord1fARB
);
630 free_funcs( &tnl
->dfn_cache
.MultiTexCoord1fvARB
);