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 fprintf(stderr
, "%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 fprintf(stderr
, "%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 fprintf(stderr
, "copy_vertex %d\n",
180 tnl
->primlist
[tnl
->nrprims
].start
+ n
);
182 for (i
= 0 ; i
< tnl
->vertex_size
; i
++) {
187 /* NOTE: This actually reads the copied vertices back from uncached
188 * memory. Could also use the counter/notify mechanism to populate
189 * tmp on the fly as vertices are generated.
191 static GLuint
copy_wrapped_verts( TNLcontext
*tnl
, GLfloat (*tmp
)[15] )
194 GLuint nr
= (tnl
->initial_counter
- tnl
->counter
) - tnl
->primlist
[tnl
->nrprims
].start
;
196 if (MESA_VERBOSE
& DEBUG_VFMT
)
197 fprintf(stderr
, "%s %d verts\n", __FUNCTION__
, nr
);
199 switch( tnl
->prim
[0] )
205 for (i
= 0 ; i
< ovf
; i
++)
206 copy_vertex( tnl
, nr
-ovf
+i
, tmp
[i
] );
210 for (i
= 0 ; i
< ovf
; i
++)
211 copy_vertex( tnl
, nr
-ovf
+i
, tmp
[i
] );
215 for (i
= 0 ; i
< ovf
; i
++)
216 copy_vertex( tnl
, nr
-ovf
+i
, tmp
[i
] );
221 copy_vertex( tnl
, nr
-1, tmp
[0] );
224 case GL_TRIANGLE_FAN
:
229 copy_vertex( tnl
, 0, tmp
[0] );
232 copy_vertex( tnl
, 0, tmp
[0] );
233 copy_vertex( tnl
, nr
-1, tmp
[1] );
236 case GL_TRIANGLE_STRIP
:
237 ovf
= MIN2( nr
-1, 2 );
238 for (i
= 0 ; i
< ovf
; i
++)
239 copy_vertex( tnl
, nr
-ovf
+i
, tmp
[i
] );
242 ovf
= MIN2( nr
-1, 2 );
243 if (nr
> 2) ovf
+= nr
&1;
244 for (i
= 0 ; i
< ovf
; i
++)
245 copy_vertex( tnl
, nr
-ovf
+i
, tmp
[i
] );
255 /* Extend for vertex-format changes on wrap:
257 static void wrap_buffer( void )
259 TNLcontext
*tnl
= tnl
->tnl
;
263 if (MESA_VERBOSE
& (DEBUG_VFMT
|DEBUG_PRIMS
))
264 fprintf(stderr
, "%s %d\n", __FUNCTION__
,
265 tnl
->initial_counter
- tnl
->counter
);
267 /* Don't deal with parity. *** WONT WORK FOR COMPILE
269 if ((((tnl
->initial_counter
- tnl
->counter
) -
270 tnl
->primlist
[tnl
->nrprims
].start
) & 1)) {
272 tnl
->initial_counter
++;
276 /* Copy vertices out of dma:
278 nrverts
= copy_dma_verts( tnl
, tmp
);
280 if (MESA_VERBOSE
& DEBUG_VFMT
)
281 fprintf(stderr
, "%d vertices to copy\n", nrverts
);
284 /* Finish the prim at this point:
286 note_last_prim( tnl
, 0 );
289 /* Reset counter, dmaptr
291 tnl
->dmaptr
= (int *)(tnl
->dma
.current
.ptr
+ tnl
->dma
.current
.address
);
292 tnl
->counter
= (tnl
->dma
.current
.end
- tnl
->dma
.current
.ptr
) /
293 (tnl
->vertex_size
* 4);
295 tnl
->initial_counter
= tnl
->counter
;
296 tnl
->notify
= wrap_buffer
;
298 tnl
->dma
.flush
= flush_prims
;
299 start_prim( tnl
, tnl
->prim
[0] );
302 /* Reemit saved vertices
303 * *** POSSIBLY IN NEW FORMAT
304 * --> Can't always extend at end of vertex?
306 for (i
= 0 ; i
< nrverts
; i
++) {
307 if (MESA_VERBOSE
& DEBUG_VERTS
) {
309 fprintf(stderr
, "re-emit vertex %d to %p\n", i
, tnl
->dmaptr
);
310 if (MESA_VERBOSE
& DEBUG_VERBOSE
)
311 for (j
= 0 ; j
< tnl
->vertex_size
; j
++)
312 fprintf(stderr
, "\t%08x/%f\n", *(int*)&tmp
[i
][j
], tmp
[i
][j
]);
315 memcpy( tnl
->dmaptr
, tmp
[i
], tnl
->vertex_size
* 4 );
316 tnl
->dmaptr
+= tnl
->vertex_size
;
323 /* Always follow data, don't try to predict what's necessary.
325 static GLboolean
check_vtx_fmt( GLcontext
*ctx
)
327 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
329 if (ctx
->Driver
.NeedFlush
& FLUSH_UPDATE_CURRENT
)
330 ctx
->Driver
.FlushVertices( ctx
, FLUSH_UPDATE_CURRENT
);
334 tnl
->vertex_format
= VERT_BIT_POS
;
335 tnl
->prim
= &ctx
->Driver
.CurrentExecPrimitive
;
338 /* Currently allow the full 4 components per attrib. Can use the
339 * mechanism from radeon driver color handling to reduce this (and
340 * also to store ubyte colors where these are incoming). This
341 * won't work for compile mode.
343 * Only adding components when they are first received eliminates
344 * the need for displaylist fixup, as there are no 'empty' slots
345 * at the start of buffers.
347 for (i
= 0 ; i
< 16 ; i
++) {
349 tnl
->attribptr
[i
] = &tnl
->vertex
[tnl
->vertex_size
].f
;
350 tnl
->vertex_size
+= 4;
351 tnl
->attribptr
[i
][0] = ctx
->Current
.Attrib
[i
][0];
352 tnl
->attribptr
[i
][1] = ctx
->Current
.Attrib
[i
][1];
353 tnl
->attribptr
[i
][2] = ctx
->Current
.Attrib
[i
][2];
354 tnl
->attribptr
[i
][3] = ctx
->Current
.Attrib
[i
][3];
357 tnl
->attribptr
[i
] = ctx
->Current
.Attrib
[i
];
362 for (i
= 16 ; i
< 18 ; i
++)
367 for (i
= 18 ; i
< 28 ; i
++)
372 for (i
= 28 ; i
< 29 ; i
++)
376 if (tnl
->installed_vertex_format
!= tnl
->vertex_format
) {
377 if (MESA_VERBOSE
& DEBUG_VFMT
)
378 fprintf(stderr
, "reinstall on vertex_format change\n");
379 _mesa_install_exec_vtxfmt( ctx
, &tnl
->vtxfmt
);
380 tnl
->installed_vertex_format
= tnl
->vertex_format
;
387 void _tnl_InvalidateVtxfmt( GLcontext
*ctx
)
389 tnl
->recheck
= GL_TRUE
;
390 tnl
->fell_back
= GL_FALSE
;
396 static void _tnl_ValidateVtxfmt( GLcontext
*ctx
)
398 if (MESA_VERBOSE
& DEBUG_VFMT
)
399 fprintf(stderr
, "%s\n", __FUNCTION__
);
401 if (ctx
->Driver
.NeedFlush
)
402 ctx
->Driver
.FlushVertices( ctx
, ctx
->Driver
.NeedFlush
);
404 tnl
->recheck
= GL_FALSE
;
406 if (check_vtx_fmt( ctx
)) {
407 if (!tnl
->installed
) {
408 if (MESA_VERBOSE
& DEBUG_VFMT
)
409 fprintf(stderr
, "reinstall (new install)\n");
411 _mesa_install_exec_vtxfmt( ctx
, &tnl
->vtxfmt
);
412 ctx
->Driver
.FlushVertices
= _tnl_FlushVertices
;
413 tnl
->installed
= GL_TRUE
;
416 fprintf(stderr
, "%s: already installed", __FUNCTION__
);
419 if (MESA_VERBOSE
& DEBUG_VFMT
)
420 fprintf(stderr
, "%s: failed\n", __FUNCTION__
);
422 if (tnl
->installed
) {
423 if (tnl
->tnl
->dma
.flush
)
424 tnl
->tnl
->dma
.flush( tnl
->tnl
);
425 _tnl_wakeup_exec( ctx
);
426 tnl
->installed
= GL_FALSE
;
437 static void _tnl_Begin( GLenum mode
)
439 GLcontext
*ctx
= tnl
->context
;
440 TNLcontext
*tnl
= tnl
->tnl
;
442 if (MESA_VERBOSE
& DEBUG_VFMT
)
443 fprintf(stderr
, "%s\n", __FUNCTION__
);
445 if (mode
> GL_POLYGON
) {
446 _mesa_error( ctx
, GL_INVALID_ENUM
, "glBegin" );
450 if (tnl
->prim
[0] != GL_POLYGON
+1) {
451 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
456 _mesa_update_state( ctx
);
459 _tnl_ValidateVtxfmt( ctx
);
461 if (tnl
->dma
.flush
&& tnl
->counter
< 12) {
462 if (MESA_VERBOSE
& DEBUG_VFMT
)
463 fprintf(stderr
, "%s: flush almost-empty buffers\n", __FUNCTION__
);
467 if (!tnl
->dma
.flush
) {
468 if (tnl
->dma
.current
.ptr
+ 12*tnl
->vertex_size
*4 >
469 tnl
->dma
.current
.end
) {
471 _tnl_RefillCurrentDmaRegion( tnl
);
474 tnl
->dmaptr
= (int *)(tnl
->dma
.current
.address
+ tnl
->dma
.current
.ptr
);
475 tnl
->counter
= (tnl
->dma
.current
.end
- tnl
->dma
.current
.ptr
) /
476 (tnl
->vertex_size
* 4);
478 tnl
->initial_counter
= tnl
->counter
;
479 tnl
->notify
= wrap_buffer
;
480 tnl
->dma
.flush
= flush_prims
;
481 tnl
->context
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
486 start_prim( tnl
, mode
| PRIM_BEGIN
);
493 static void _tnl_End( void )
495 TNLcontext
*tnl
= tnl
->tnl
;
496 GLcontext
*ctx
= tnl
->context
;
498 if (MESA_VERBOSE
& DEBUG_VFMT
)
499 fprintf(stderr
, "%s\n", __FUNCTION__
);
501 if (tnl
->prim
[0] == GL_POLYGON
+1) {
502 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
506 note_last_prim( tnl
, PRIM_END
);
507 tnl
->prim
[0] = GL_POLYGON
+1;
511 static void _tnl_FlushVertices( GLcontext
*ctx
, GLuint flags
)
513 if (MESA_VERBOSE
& DEBUG_VFMT
)
514 fprintf(stderr
, "%s\n", __FUNCTION__
);
516 assert(tnl
->installed
);
518 if (flags
& FLUSH_UPDATE_CURRENT
) {
519 _tnl_copy_to_current( ctx
);
520 if (MESA_VERBOSE
& DEBUG_VFMT
)
521 fprintf(stderr
, "reinstall on update_current\n");
522 _mesa_install_exec_vtxfmt( ctx
, &tnl
->vtxfmt
);
523 ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
526 if (flags
& FLUSH_STORED_VERTICES
) {
527 TNLcontext
*tnl
= TNL_CONTEXT( ctx
);
528 assert (tnl
->dma
.flush
== 0 ||
529 tnl
->dma
.flush
== flush_prims
);
530 if (tnl
->dma
.flush
== flush_prims
)
531 flush_prims( TNL_CONTEXT( ctx
) );
532 ctx
->Driver
.NeedFlush
&= ~FLUSH_STORED_VERTICES
;
538 /* At this point, don't expect very many versions of each function to
539 * be generated, so not concerned about freeing them?
543 static void _tnl_InitVtxfmt( GLcontext
*ctx
)
545 GLvertexformat
*vfmt
= &(tnl
->vtxfmt
);
547 MEMSET( vfmt
, 0, sizeof(GLvertexformat
) );
549 /* Hook in chooser functions for codegen, etc:
551 _tnl_InitVtxfmtChoosers( vfmt
);
553 /* Handled fully in supported states, but no codegen:
555 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
556 vfmt
->Rectf
= _mesa_noop_Rectf
; /* generic helper */
557 vfmt
->Begin
= _tnl_Begin
;
558 vfmt
->End
= _tnl_End
;
561 tnl
->tnl
= TNL_CONTEXT(ctx
);
562 tnl
->prim
= &ctx
->Driver
.CurrentExecPrimitive
;
565 make_empty_list( &tnl
->dfn_cache
.Vertex2f
);
566 make_empty_list( &tnl
->dfn_cache
.Vertex2fv
);
567 make_empty_list( &tnl
->dfn_cache
.Vertex3f
);
568 make_empty_list( &tnl
->dfn_cache
.Vertex3fv
);
569 make_empty_list( &tnl
->dfn_cache
.Color4ub
);
570 make_empty_list( &tnl
->dfn_cache
.Color4ubv
);
571 make_empty_list( &tnl
->dfn_cache
.Color3ub
);
572 make_empty_list( &tnl
->dfn_cache
.Color3ubv
);
573 make_empty_list( &tnl
->dfn_cache
.Color4f
);
574 make_empty_list( &tnl
->dfn_cache
.Color4fv
);
575 make_empty_list( &tnl
->dfn_cache
.Color3f
);
576 make_empty_list( &tnl
->dfn_cache
.Color3fv
);
577 make_empty_list( &tnl
->dfn_cache
.SecondaryColor3fEXT
);
578 make_empty_list( &tnl
->dfn_cache
.SecondaryColor3fvEXT
);
579 make_empty_list( &tnl
->dfn_cache
.SecondaryColor3ubEXT
);
580 make_empty_list( &tnl
->dfn_cache
.SecondaryColor3ubvEXT
);
581 make_empty_list( &tnl
->dfn_cache
.Normal3f
);
582 make_empty_list( &tnl
->dfn_cache
.Normal3fv
);
583 make_empty_list( &tnl
->dfn_cache
.TexCoord2f
);
584 make_empty_list( &tnl
->dfn_cache
.TexCoord2fv
);
585 make_empty_list( &tnl
->dfn_cache
.TexCoord1f
);
586 make_empty_list( &tnl
->dfn_cache
.TexCoord1fv
);
587 make_empty_list( &tnl
->dfn_cache
.MultiTexCoord2fARB
);
588 make_empty_list( &tnl
->dfn_cache
.MultiTexCoord2fvARB
);
589 make_empty_list( &tnl
->dfn_cache
.MultiTexCoord1fARB
);
590 make_empty_list( &tnl
->dfn_cache
.MultiTexCoord1fvARB
);
592 _tnl_InitCodegen( &tnl
->codegen
);
595 static void free_funcs( struct dynfn
*l
)
597 struct dynfn
*f
, *tmp
;
598 foreach_s (f
, tmp
, l
) {
599 remove_from_list( f
);
600 ALIGN_FREE( f
->code
);
606 static void _tnl_DestroyVtxfmt( GLcontext
*ctx
)
609 free_funcs( &tnl
->dfn_cache
.Vertex2f
);
610 free_funcs( &tnl
->dfn_cache
.Vertex2fv
);
611 free_funcs( &tnl
->dfn_cache
.Vertex3f
);
612 free_funcs( &tnl
->dfn_cache
.Vertex3fv
);
613 free_funcs( &tnl
->dfn_cache
.Color4ub
);
614 free_funcs( &tnl
->dfn_cache
.Color4ubv
);
615 free_funcs( &tnl
->dfn_cache
.Color3ub
);
616 free_funcs( &tnl
->dfn_cache
.Color3ubv
);
617 free_funcs( &tnl
->dfn_cache
.Color4f
);
618 free_funcs( &tnl
->dfn_cache
.Color4fv
);
619 free_funcs( &tnl
->dfn_cache
.Color3f
);
620 free_funcs( &tnl
->dfn_cache
.Color3fv
);
621 free_funcs( &tnl
->dfn_cache
.SecondaryColor3ubEXT
);
622 free_funcs( &tnl
->dfn_cache
.SecondaryColor3ubvEXT
);
623 free_funcs( &tnl
->dfn_cache
.SecondaryColor3fEXT
);
624 free_funcs( &tnl
->dfn_cache
.SecondaryColor3fvEXT
);
625 free_funcs( &tnl
->dfn_cache
.Normal3f
);
626 free_funcs( &tnl
->dfn_cache
.Normal3fv
);
627 free_funcs( &tnl
->dfn_cache
.TexCoord2f
);
628 free_funcs( &tnl
->dfn_cache
.TexCoord2fv
);
629 free_funcs( &tnl
->dfn_cache
.TexCoord1f
);
630 free_funcs( &tnl
->dfn_cache
.TexCoord1fv
);
631 free_funcs( &tnl
->dfn_cache
.MultiTexCoord2fARB
);
632 free_funcs( &tnl
->dfn_cache
.MultiTexCoord2fvARB
);
633 free_funcs( &tnl
->dfn_cache
.MultiTexCoord1fARB
);
634 free_funcs( &tnl
->dfn_cache
.MultiTexCoord1fvARB
);