Move dri_util.[ch] and glcontextmodes.[ch] from dri_client to common.
[mesa.git] / src / mesa / drivers / dri / radeon / radeon_subset_vtx.c
1 /**
2 * \file radeon_subset_vtx.c
3 * \brief Vertex buffering.
4 *
5 * \author Keith Whitwell <keith@tungstengraphics.com>
6 */
7
8 /*
9 * Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
10 * Tungsten Graphics Inc., Cedar Park, Texas.
11 *
12 * All Rights Reserved.
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a
15 * copy of this software and associated documentation files (the "Software"),
16 * to deal in the Software without restriction, including without limitation
17 * on the rights to use, copy, modify, merge, publish, distribute, sub
18 * license, and/or sell copies of the Software, and to permit persons to whom
19 * the Software is furnished to do so, subject to the following conditions:
20 *
21 * The above copyright notice and this permission notice (including the next
22 * paragraph) shall be included in all copies or substantial portions of the
23 * Software.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
28 * ATI, TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
29 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
30 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
31 * USE OR OTHER DEALINGS IN THE SOFTWARE.
32 *
33 */
34
35 /* $XFree86$ */
36
37 #include "glheader.h"
38 #include "imports.h"
39 #include "api_noop.h"
40 #include "context.h"
41 /*#include "mmath.h" */
42 #include "mtypes.h"
43 #include "enums.h"
44 #include "glapi.h"
45 #include "colormac.h"
46 #include "state.h"
47
48 #include "radeon_context.h"
49 #include "radeon_state.h"
50 #include "radeon_ioctl.h"
51 #include "radeon_subset.h"
52
53 /**
54 * \brief Union for vertex data.
55 */
56 union vertex_dword {
57 float f; /**< \brief floating point value */
58 int i; /**< \brief integer point value */
59 };
60
61
62 /**
63 * \brief Maximum number of dwords per vertex.
64 *
65 * Defined as 10 to hold: \code xyzw rgba st \endcode
66 */
67 #define MAX_VERTEX_DWORDS 10
68
69
70 /**
71 * \brief Global vertex buffer data.
72 */
73 static struct vb_t {
74 /**
75 * \brief Notification mechanism.
76 *
77 * These are treated as a stack to allow us to do things like build quads in
78 * temporary storage and then emit them as triangles.
79 */
80 struct {
81 GLint vertspace; /**< \brief free vertices count */
82 GLint initial_vertspace; /**< \brief total vertices count */
83 GLint *dmaptr; /**< \brief */
84 void (*notify)( void ); /**< \brief notification callback */
85 } stack[2];
86
87 /**
88 * \brief Storage for current vertex.
89 */
90 union vertex_dword vertex[MAX_VERTEX_DWORDS];
91
92 /**
93 * \brief Temporary storage for quads, etc.
94 */
95 union vertex_dword vertex_store[MAX_VERTEX_DWORDS * 4];
96
97 /**
98 * \name Color/texture
99 *
100 * Pointers to either vertex or ctx->Current.Attrib, depending on whether
101 * color/texture participates in the current vertex.
102 */
103 /*@{*/
104 GLfloat *floatcolorptr; /**< \brief color */
105 GLfloat *texcoordptr; /**< \brief texture */
106 /*@}*/
107
108 /**
109 * \brief Pointer to the GL context.
110 */
111 GLcontext *context;
112
113 /**
114 * \brief Active primitive.
115 *
116 * \note May differ from ctx->Driver.CurrentExecPrimitive.
117 */
118 /*@{*/
119 GLenum prim; /**< \brief primitive */
120 GLuint vertex_format; /**< \brief vertex format */
121 GLint vertex_size; /**< \brief vertex size */
122 GLboolean recheck; /**< \brief set if it's needed to validate this information */
123 /*@}*/
124 } vb;
125
126
127 static void radeonFlushVertices( GLcontext *, GLuint );
128
129
130 /**
131 * \brief Primitive information table.
132 */
133 static struct prims_t {
134 int start, /**< \brief vertex count for the starting primitive */
135 incr, /**< \brief vertex increment for a further primitive */
136 hwprim; /**< \brief hardware primitive */
137 } prims[10] = {
138 { 1, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_POINT },
139 { 2, 2, RADEON_CP_VC_CNTL_PRIM_TYPE_LINE },
140 { 2, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP },
141 { 2, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP },
142 { 3, 3, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST },
143 { 3, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP },
144 { 3, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN },
145 { 4, 4, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST },
146 { 4, 2, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP },
147 { 3, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN },
148 };
149
150
151 /**
152 * \brief Finish the primitive in the vertex buffer.
153 *
154 * \param rmesa Radeon context.
155 *
156 * Truncates any redundant vertices off the end of the buffer, emit the
157 * remaining vertices and advances the current DMA region.
158 */
159 static void finish_prim( radeonContextPtr rmesa )
160 {
161 GLuint prim_end = vb.stack[0].initial_vertspace - vb.stack[0].vertspace;
162
163 /* Too few vertices? (eg: 2 vertices for a triangles prim?)
164 */
165 if (prim_end < prims[vb.prim].start)
166 return;
167
168 /* Drop redundant vertices off end of primitive. (eg: 5 vertices
169 * for triangles prim?)
170 */
171 prim_end -= (prim_end - prims[vb.prim].start) % prims[vb.prim].incr;
172
173 radeonEmitVertexAOS( rmesa, vb.vertex_size, GET_START(&rmesa->dma.current) );
174
175 radeonEmitVbufPrim( rmesa, vb.vertex_format,
176 prims[vb.prim].hwprim | rmesa->tcl.tcl_flag,
177 prim_end );
178
179 rmesa->dma.current.ptr =
180 rmesa->dma.current.start += prim_end * vb.vertex_size * 4;
181 }
182
183
184 /**
185 * \brief Copy a vertex from the current DMA region
186 *
187 * \param rmesa Radeon context.
188 * \param n vertex index relative to the current DMA region.
189 * \param dst destination pointer.
190 *
191 * Used internally by copy_dma_verts().
192 */
193 static void copy_vertex( radeonContextPtr rmesa, GLuint n, GLfloat *dst )
194 {
195 GLuint i;
196 GLfloat *src = (GLfloat *)(rmesa->dma.current.address +
197 rmesa->dma.current.ptr +
198 n * vb.vertex_size * 4);
199
200 for (i = 0 ; i < vb.vertex_size; i++)
201 dst[i] = src[i];
202 }
203
204
205 /**
206 * \brief Copy last vertices from the current DMA buffer to resume in a new buffer.
207 *
208 * \param rmesa Radeon context.
209 * \param tmp destination buffer.
210 *
211 * Takes from the current DMA buffer the last vertices necessary to resume in a
212 * new buffer, according to the current primitive. Uses internally
213 * copy_vertex() for the vertex copying.
214 *
215 */
216 static GLuint copy_dma_verts( radeonContextPtr rmesa,
217 GLfloat (*tmp)[MAX_VERTEX_DWORDS] )
218 {
219 GLuint ovf, i;
220 GLuint nr = vb.stack[0].initial_vertspace - vb.stack[0].vertspace;
221
222 switch( vb.prim )
223 {
224 case GL_POINTS:
225 return 0;
226 case GL_LINES:
227 ovf = nr&1;
228 for (i = 0 ; i < ovf ; i++)
229 copy_vertex( rmesa, nr-ovf+i, tmp[i] );
230 return i;
231 case GL_LINE_STRIP:
232 if (nr == 0)
233 return 0;
234 copy_vertex( rmesa, nr-1, tmp[0] );
235 return 1;
236 case GL_LINE_LOOP:
237 case GL_TRIANGLE_FAN:
238 case GL_POLYGON:
239 if (nr == 0)
240 return 0;
241 else if (nr == 1) {
242 copy_vertex( rmesa, 0, tmp[0] );
243 return 1;
244 } else {
245 copy_vertex( rmesa, 0, tmp[0] );
246 copy_vertex( rmesa, nr-1, tmp[1] );
247 return 2;
248 }
249 case GL_TRIANGLES:
250 ovf = nr % 3;
251 for (i = 0 ; i < ovf ; i++)
252 copy_vertex( rmesa, nr-ovf+i, tmp[i] );
253 return i;
254 case GL_QUADS:
255 ovf = nr % 4;
256 for (i = 0 ; i < ovf ; i++)
257 copy_vertex( rmesa, nr-ovf+i, tmp[i] );
258 return i;
259 case GL_TRIANGLE_STRIP:
260 case GL_QUAD_STRIP:
261 ovf = MIN2(nr, 2);
262 for (i = 0 ; i < ovf ; i++)
263 copy_vertex( rmesa, nr-ovf+i, tmp[i] );
264 return i;
265 default:
266 return 0;
267 }
268 }
269
270 static void notify_wrap_buffer( void );
271
272 /**
273 * \brief Resets the vertex buffer notification mechanism.
274 *
275 * Fills in vb_t::stack with the values from the current DMA region in
276 * radeon_dma::current and sets the notification callback to
277 * notify_wrap_buffer().
278 */
279 static void reset_notify( void )
280 {
281 radeonContextPtr rmesa = RADEON_CONTEXT( vb.context );
282
283 vb.stack[0].dmaptr = (int *)(rmesa->dma.current.address +
284 rmesa->dma.current.ptr);
285 vb.stack[0].vertspace = ((rmesa->dma.current.end - rmesa->dma.current.ptr) /
286 (vb.vertex_size * 4));
287 vb.stack[0].vertspace &= ~1; /* even numbers only -- avoid tristrip parity */
288 vb.stack[0].initial_vertspace = vb.stack[0].vertspace;
289 vb.stack[0].notify = notify_wrap_buffer;
290 }
291
292 /**
293 * \brief Full buffer notification callback.
294 *
295 * Makes a copy of the necessary vertices of the current buffer via
296 * copy_dma_verts(), gets and resets new buffer via radeon and re-emits the
297 * saved vertices.
298 */
299 static void notify_wrap_buffer( void )
300 {
301 GLcontext *ctx = vb.context;
302 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
303 GLfloat tmp[3][MAX_VERTEX_DWORDS];
304 GLuint i, nrverts = 0;
305
306 /* Copy vertices out of dma:
307 */
308 nrverts = copy_dma_verts( rmesa, tmp );
309 finish_prim( rmesa );
310
311 /* Get new buffer
312 */
313 radeonRefillCurrentDmaRegion( rmesa );
314
315 /* Reset vertspace[0], dmaptr
316 */
317 reset_notify();
318
319 /* Reemit saved vertices
320 */
321 for (i = 0 ; i < nrverts; i++) {
322 memcpy( vb.stack[0].dmaptr, tmp[i], vb.vertex_size * 4 );
323 vb.stack[0].dmaptr += vb.vertex_size;
324 vb.stack[0].vertspace--;
325 }
326 }
327
328
329 static void notify_noop( void )
330 {
331 vb.stack[0].dmaptr = (int *)vb.vertex;
332 vb.stack[0].notify = notify_noop;
333 vb.stack[0].vertspace = 1;
334 }
335
336 /**
337 * \brief Pop the notification mechanism stack.
338 *
339 * Simply copy the second stack array element into the first.
340 *
341 * \sa vb_t::stack and push_notify().
342 */
343 static void pop_notify( void )
344 {
345 vb.stack[0] = vb.stack[1];
346 }
347
348 /**
349 * \brief Push the notification mechanism stack.
350 *
351 * \param notify new notify callback for the stack head.
352 * \param space space available for vertices in \p store.
353 * \param store buffer where to store the vertices.
354 *
355 * Copy the second stack array element into the first and makes the stack head
356 * use the given resources.
357 *
358 * \sa vb_t::stack and pop_notify().
359 */
360 static void push_notify( void (*notify)( void ), int space,
361 union vertex_dword *store )
362 {
363 vb.stack[1] = vb.stack[0];
364 vb.stack[0].notify = notify;
365 vb.stack[0].initial_vertspace = space;
366 vb.stack[0].vertspace = space;
367 vb.stack[0].dmaptr = (int *)store;
368 }
369
370
371 /**
372 * \brief Emit a stored vertex (in vb_t::vertex_store) to DMA.
373 *
374 * \param v vertex index.
375 *
376 * Adds the vertex into the current vertex buffer and calls the notification
377 * callback vb_t::notify().
378 */
379 static void emit_vertex( int v )
380 {
381 int i, *tmp = (int *)vb.vertex_store + v * vb.vertex_size;
382
383 for (i = 0 ; i < vb.vertex_size ; i++)
384 *vb.stack[0].dmaptr++ = *tmp++;
385
386 if (--vb.stack[0].vertspace == 0)
387 vb.stack[0].notify();
388 }
389
390
391 /**
392 * \brief Emit a quad (in vb_t::vertex_store) to DMA as two triangles.
393 *
394 * \param v0 first vertex index.
395 * \param v1 second vertex index.
396 * \param v2 third vertex index.
397 * \param v3 fourth vertex index.
398 *
399 * Calls emit_vertex() to emit the triangles' vertices.
400 */
401 static void emit_quad( int v0, int v1, int v2, int v3 )
402 {
403 emit_vertex( v0 ); emit_vertex( v1 ); emit_vertex( v3 );
404 emit_vertex( v1 ); emit_vertex( v2 ); emit_vertex( v3 );
405 }
406
407 /**
408 * \brief Every fourth vertex in a quad primitive, this is called to emit it.
409 *
410 * Pops the notification stack, calls emit_quad() and pushes the notification
411 * stack again, with itself and the vb_t::vertex_store to process another four
412 * vertices.
413 */
414 static void notify_quad( void )
415 {
416 pop_notify();
417 emit_quad( 0, 1, 2, 3 );
418 push_notify( notify_quad, 4, vb.vertex_store );
419 }
420
421 static void notify_qstrip1( void );
422
423 /**
424 * \brief After the 4th vertex, emit either a quad or a flipped quad each two
425 * vertices.
426 *
427 * Pops the notification stack, calls emit_quad() with the flipped vertices and
428 * pushes the notification stack again, with notify_qstrip1() and the
429 * vb_t::vertex_store to process another two vertices.
430 *
431 * \sa notify_qstrip1().
432 */
433 static void notify_qstrip0( void )
434 {
435 pop_notify();
436 emit_quad( 0, 1, 3, 2 );
437 push_notify( notify_qstrip1, 2, vb.vertex_store );
438 }
439
440 /**
441 * \brief After the 4th vertex, emit either a quad or a flipped quad each two
442 * vertices.
443 *
444 * Pops the notification stack, calls emit_quad() with the straight vertices
445 * and pushes the notification stack again, with notify_qstrip0() and the
446 * vb_t::vertex_store to process another two vertices.
447 *
448 * \sa notify_qstrip0().
449 */
450 static void notify_qstrip1( void )
451 {
452 pop_notify();
453 emit_quad( 2, 3, 1, 0 );
454 push_notify( notify_qstrip0, 2, vb.vertex_store + 2*vb.vertex_size );
455 }
456
457 /**
458 * \brief Emit the saved vertex (but hang on to it for later).
459 *
460 * Continue processing this primitive as a linestrip.
461 *
462 * Pops the notification stack and calls emit_quad with the first vertex.
463 */
464 static void notify_lineloop0( void )
465 {
466 pop_notify();
467 emit_vertex(0);
468 }
469
470 /**
471 * \brief Invalidate the current vertex format.
472 *
473 * \param ctx GL context.
474 *
475 * Sets the vb_t::recheck flag.
476 */
477 void radeonVtxfmtInvalidate( GLcontext *ctx )
478 {
479 vb.recheck = GL_TRUE;
480 }
481
482
483 /**
484 * \brief Validate the vertex format from the context.
485 *
486 * \param ctx GL context.
487 *
488 * Signals a new primitive and determines the appropriate vertex format and
489 * size. Points vb_t::floatcolorptr and vb_t::texcoordptr to the current vertex
490 * and sets them to the current color and texture attributes.
491 *
492 * Clears the vb_t::recheck flag on exit.
493 */
494 static void radeonVtxfmtValidate( GLcontext *ctx )
495 {
496 radeonContextPtr rmesa = RADEON_CONTEXT( ctx );
497 GLuint ind = (RADEON_CP_VC_FRMT_Z |
498 RADEON_CP_VC_FRMT_FPCOLOR |
499 RADEON_CP_VC_FRMT_FPALPHA);
500
501 if (ctx->Driver.NeedFlush)
502 ctx->Driver.FlushVertices( ctx, ctx->Driver.NeedFlush );
503
504 if (ctx->Texture.Unit[0]._ReallyEnabled)
505 ind |= RADEON_CP_VC_FRMT_ST0;
506
507 RADEON_NEWPRIM(rmesa);
508 vb.vertex_format = ind;
509 vb.vertex_size = 3;
510
511 /* Would prefer to use ubyte floats in the vertex:
512 */
513 vb.floatcolorptr = &vb.vertex[vb.vertex_size].f;
514 vb.vertex_size += 4;
515 vb.floatcolorptr[0] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0];
516 vb.floatcolorptr[1] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1];
517 vb.floatcolorptr[2] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2];
518 vb.floatcolorptr[3] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3];
519
520 if (ind & RADEON_CP_VC_FRMT_ST0) {
521 vb.texcoordptr = &vb.vertex[vb.vertex_size].f;
522 vb.vertex_size += 2;
523 vb.texcoordptr[0] = ctx->Current.Attrib[VERT_ATTRIB_TEX0][0];
524 vb.texcoordptr[1] = ctx->Current.Attrib[VERT_ATTRIB_TEX0][1];
525 }
526 else
527 vb.texcoordptr = ctx->Current.Attrib[VERT_ATTRIB_TEX0];
528
529 vb.recheck = GL_FALSE;
530 ctx->Driver.NeedFlush = FLUSH_UPDATE_CURRENT;
531 }
532
533
534 #define RESET_STIPPLE() do { \
535 RADEON_STATECHANGE( rmesa, lin ); \
536 radeonEmitState( rmesa ); \
537 } while (0)
538
539 #define AUTO_STIPPLE( mode ) do { \
540 RADEON_STATECHANGE( rmesa, lin ); \
541 if (mode) \
542 rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] |= \
543 RADEON_LINE_PATTERN_AUTO_RESET; \
544 else \
545 rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] &= \
546 ~RADEON_LINE_PATTERN_AUTO_RESET; \
547 radeonEmitState( rmesa ); \
548 } while (0)
549
550
551 /**
552 * \brief Process glBegin().
553 *
554 * \param mode primitive.
555 */
556 static void radeon_Begin( GLenum mode )
557 {
558 GLcontext *ctx = vb.context;
559 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
560 GLuint se_cntl;
561
562 if (mode > GL_POLYGON) {
563 _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" );
564 return;
565 }
566
567 if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
568 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
569 return;
570 }
571
572 if (ctx->NewState)
573 _mesa_update_state( ctx );
574
575 if (rmesa->NewGLState)
576 radeonValidateState( ctx );
577
578 if (vb.recheck)
579 radeonVtxfmtValidate( ctx );
580
581 /* Do we need to grab a new DMA region for the vertices?
582 */
583 if (rmesa->dma.current.ptr + 12*vb.vertex_size*4 > rmesa->dma.current.end) {
584 RADEON_NEWPRIM( rmesa );
585 radeonRefillCurrentDmaRegion( rmesa );
586 }
587
588 reset_notify();
589 vb.prim = ctx->Driver.CurrentExecPrimitive = mode;
590 se_cntl = rmesa->hw.set.cmd[SET_SE_CNTL] | RADEON_FLAT_SHADE_VTX_LAST;
591
592 if (ctx->Line.StippleFlag &&
593 (mode == GL_LINES ||
594 mode == GL_LINE_LOOP ||
595 mode == GL_LINE_STRIP))
596 RESET_STIPPLE();
597
598 switch( mode ) {
599 case GL_LINES:
600 if (ctx->Line.StippleFlag)
601 AUTO_STIPPLE( GL_TRUE );
602 break;
603 case GL_LINE_LOOP:
604 vb.prim = GL_LINE_STRIP;
605 push_notify( notify_lineloop0, 1, vb.vertex_store );
606 break;
607 case GL_QUADS:
608 vb.prim = GL_TRIANGLES;
609 push_notify( notify_quad, 4, vb.vertex_store );
610 break;
611 case GL_QUAD_STRIP:
612 if (ctx->_TriangleCaps & DD_FLATSHADE) {
613 vb.prim = GL_TRIANGLES;
614 push_notify( notify_qstrip0, 4, vb.vertex_store );
615 }
616 break;
617 case GL_POLYGON:
618 if (ctx->_TriangleCaps & DD_FLATSHADE)
619 se_cntl &= ~RADEON_FLAT_SHADE_VTX_LAST;
620 break;
621 default:
622 break;
623 }
624
625 if (se_cntl != rmesa->hw.set.cmd[SET_SE_CNTL]) {
626 RADEON_STATECHANGE( rmesa, set );
627 rmesa->hw.set.cmd[SET_SE_CNTL] = se_cntl;
628 }
629 }
630
631
632 /**
633 * \brief Process glEnd().
634 *
635 */
636 static void radeon_End( void )
637 {
638 GLcontext *ctx = vb.context;
639 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
640
641 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
642 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
643 return;
644 }
645
646 /* Need to finish a line loop?
647 */
648 if (ctx->Driver.CurrentExecPrimitive == GL_LINE_LOOP)
649 emit_vertex( 0 );
650
651 /* Need to pop off quads/quadstrip/etc notification?
652 */
653 if (vb.stack[0].notify != notify_wrap_buffer)
654 pop_notify();
655
656 finish_prim( rmesa );
657
658 if (ctx->Driver.CurrentExecPrimitive == GL_LINES && ctx->Line.StippleFlag)
659 AUTO_STIPPLE( GL_FALSE );
660
661 ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
662 notify_noop();
663 }
664
665
666
667 /**
668 * \brief Flush vertices.
669 *
670 * \param ctx GL context.
671 * \param flags flags.
672 *
673 * If FLUSH_UPDATE_CURRENT is et in \p flags then the current vertex attributes
674 * in the GL context is updated from vb_t::floatcolorptr and vb_t::texcoordptr.
675 */
676 static void radeonFlushVertices( GLcontext *ctx, GLuint flags )
677 {
678 if (flags & FLUSH_UPDATE_CURRENT) {
679 ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0] = vb.floatcolorptr[0];
680 ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1] = vb.floatcolorptr[1];
681 ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2] = vb.floatcolorptr[2];
682 ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = vb.floatcolorptr[3];
683
684 if (vb.vertex_format & RADEON_CP_VC_FRMT_ST0) {
685 ctx->Current.Attrib[VERT_ATTRIB_TEX0][0] = vb.texcoordptr[0];
686 ctx->Current.Attrib[VERT_ATTRIB_TEX0][1] = vb.texcoordptr[1];
687 ctx->Current.Attrib[VERT_ATTRIB_TEX0][2] = 0.0F;
688 ctx->Current.Attrib[VERT_ATTRIB_TEX0][3] = 1.0F;
689 }
690 }
691
692 ctx->Driver.NeedFlush &= ~FLUSH_STORED_VERTICES;
693 }
694
695
696 /**
697 * \brief Set current vertex coordinates.
698 *
699 * \param x x vertex coordinate.
700 * \param y y vertex coordinate.
701 * \param z z vertex coordinate.
702 *
703 * Set the current vertex coordinates. If run out of space in this buffer call
704 * the notification callback.
705 */
706 static __inline__ void radeon_Vertex3f( GLfloat x, GLfloat y, GLfloat z )
707 {
708 int i;
709
710 *vb.stack[0].dmaptr++ = *(int *)&x;
711 *vb.stack[0].dmaptr++ = *(int *)&y;
712 *vb.stack[0].dmaptr++ = *(int *)&z;
713
714 for (i = 3; i < vb.vertex_size; i++)
715 *vb.stack[0].dmaptr++ = vb.vertex[i].i;
716
717 if (--vb.stack[0].vertspace == 0)
718 vb.stack[0].notify();
719 }
720
721 /**
722 * \brief Set current vertex color.
723 *
724 * \param r red color component.
725 * \param g gree color component.
726 * \param b blue color component.
727 * \param a alpha color component.
728 *
729 * Sets the current vertex color via vb_t::floatcolorptr.
730 */
731 static __inline__ void radeon_Color4f( GLfloat r, GLfloat g,
732 GLfloat b, GLfloat a )
733 {
734 GLfloat *dest = vb.floatcolorptr;
735 dest[0] = r;
736 dest[1] = g;
737 dest[2] = b;
738 dest[3] = a;
739 }
740
741 /**
742 * \brief Set current vertex texture coordinates.
743 *
744 * \param s texture coordinate.
745 * \param t texture coordinate.
746 *
747 * Sets the current vertex color via vb_t::texcoordptr.
748 */
749 static __inline__ void radeon_TexCoord2f( GLfloat s, GLfloat t )
750 {
751 GLfloat *dest = vb.texcoordptr;
752 dest[0] = s;
753 dest[1] = t;
754 }
755
756 /**
757 * Calls radeon_Vertex3f(), which is expanded inline by the compiler to be
758 * efficient.
759 */
760 static void radeon_Vertex3fv( const GLfloat *v )
761 {
762 radeon_Vertex3f( v[0], v[1], v[2] );
763 }
764
765 /**
766 * Calls radeon_Vertex3f(), which is expanded inline by the compiler to be
767 * efficient.
768 */
769 static void radeon_Vertex2f( GLfloat x, GLfloat y )
770 {
771 radeon_Vertex3f( x, y, 0 );
772 }
773
774 /**
775 * Calls radeon_Vertex3f(), which is expanded inline by the compiler to be
776 * efficient.
777 */
778 static void radeon_Vertex2fv( const GLfloat *v )
779 {
780 radeon_Vertex3f( v[0], v[1], 0 );
781 }
782
783 /**
784 * Calls radeon_Vertex3f(), which is expanded inline by the compiler to be
785 * efficient.
786 */
787 static void radeon_Color4fv( const GLfloat *v )
788 {
789 radeon_Color4f( v[0], v[1], v[2], v[3] );
790 }
791
792 /**
793 * Calls radeon_Color4f(), which is expanded inline by the compiler to be
794 * efficient.
795 */
796 static void radeon_Color3f( GLfloat r, GLfloat g, GLfloat b )
797 {
798 radeon_Color4f( r, g, b, 1.0 );
799 }
800
801 /**
802 * Calls radeon_Color4f(), which is expanded inline by the compiler to be
803 * efficient.
804 */
805 static void radeon_Color3fv( const GLfloat *v )
806 {
807 radeon_Color4f( v[0], v[1], v[2], 1.0 );
808 }
809
810 /**
811 * Calls radeon_TexCoord2f(), which is expanded inline by the compiler to be
812 * efficient.
813 */
814 static void radeon_TexCoord2fv( const GLfloat *v )
815 {
816 radeon_TexCoord2f( v[0], v[1] );
817 }
818
819
820 /**
821 * No-op.
822 */
823 void radeonVtxfmtUnbindContext( GLcontext *ctx )
824 {
825 }
826
827 /**
828 * No-op.
829 */
830 void radeonVtxfmtMakeCurrent( GLcontext *ctx )
831 {
832 }
833
834 /**
835 * No-op.
836 */
837 void radeonVtxfmtDestroy( GLcontext *ctx )
838 {
839 }
840
841 /**
842 * \brief Software rendering fallback.
843 *
844 * \param ctx GL context.
845 * \param bit fallback bitmask.
846 * \param mode enable or disable.
847 *
848 * Does nothing except display a warning message if \p mode is set.
849 */
850 void radeonFallback( GLcontext *ctx, GLuint bit, GLboolean mode )
851 {
852 if (mode)
853 fprintf(stderr, "Warning: hit nonexistant fallback path!\n");
854 }
855
856 /**
857 * \brief Software TCL fallback.
858 *
859 * \param ctx GL context.
860 * \param bit fallback bitmask.
861 * \param mode enable or disable.
862 *
863 * Does nothing except display a warning message if \p mode is set.
864 */
865 void radeonTclFallback( GLcontext *ctx, GLuint bit, GLboolean mode )
866 {
867 if (mode)
868 fprintf(stderr, "Warning: hit nonexistant fallback path!\n");
869 }
870
871 /**
872 * \brief Called by radeonPointsBitmap() to disable TCL.
873 *
874 * \param rmesa Radeon context.
875 * \param flag whether to enable or disable TCL.
876 *
877 * Updates radeon_tcl_info::tcl_flag.
878 */
879 void radeonSubsetVtxEnableTCL( radeonContextPtr rmesa, GLboolean flag )
880 {
881 rmesa->tcl.tcl_flag = flag ? RADEON_CP_VC_CNTL_TCL_ENABLE : 0;
882 }
883
884
885
886 /**********************************************************************/
887 /** \name Noop mode for operation without focus */
888 /**********************************************************************/
889 /*@{*/
890
891
892 /**
893 * \brief Process glBegin().
894 *
895 * \param mode primitive.
896 */
897 static void radeon_noop_Begin(GLenum mode)
898 {
899 GET_CURRENT_CONTEXT(ctx);
900
901 if (mode > GL_POLYGON) {
902 _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" );
903 return;
904 }
905
906 if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
907 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
908 return;
909 }
910
911 ctx->Driver.CurrentExecPrimitive = mode;
912 }
913
914 /**
915 * \brief Process glEnd().
916 */
917 static void radeon_noop_End(void)
918 {
919 GET_CURRENT_CONTEXT(ctx);
920 ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
921 }
922
923
924 /**
925 * \brief Install the noop callbacks.
926 *
927 * \param ctx GL context.
928 *
929 * Installs the noop callbacks into the glapi table. These functions
930 * will not attempt to emit any DMA vertices, but will keep internal
931 * GL state updated. Borrows heavily from the select code.
932 */
933 static void radeon_noop_Install( GLcontext *ctx )
934 {
935 ctx->Exec->Begin = radeon_noop_Begin;
936 ctx->Exec->End = radeon_noop_End;
937
938 vb.texcoordptr = ctx->Current.Attrib[VERT_ATTRIB_TEX0];
939 vb.floatcolorptr = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
940
941 notify_noop();
942 }
943
944
945 /**
946 * \brief Setup the GL context callbacks.
947 *
948 * \param ctx GL context.
949 *
950 * Setups the GL context callbacks and links _glapi_table entries related to
951 * the glBegin()/glEnd() pairs to the functions in this module.
952 *
953 * Called by radeonCreateContext() and radeonRenderMode().
954 */
955 void radeonVtxfmtInit( GLcontext *ctx )
956 {
957 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
958 struct _glapi_table *exec = ctx->Exec;
959
960 exec->Color3f = radeon_Color3f;
961 exec->Color3fv = radeon_Color3fv;
962 exec->Color4f = radeon_Color4f;
963 exec->Color4fv = radeon_Color4fv;
964 exec->TexCoord2f = radeon_TexCoord2f;
965 exec->TexCoord2fv = radeon_TexCoord2fv;
966 exec->Vertex2f = radeon_Vertex2f;
967 exec->Vertex2fv = radeon_Vertex2fv;
968 exec->Vertex3f = radeon_Vertex3f;
969 exec->Vertex3fv = radeon_Vertex3fv;
970 exec->Begin = radeon_Begin;
971 exec->End = radeon_End;
972
973 vb.context = ctx;
974
975 ctx->Driver.FlushVertices = radeonFlushVertices;
976 ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
977
978 if (rmesa->radeonScreen->buffers) {
979 radeonVtxfmtValidate( ctx );
980 notify_noop();
981 }
982 else
983 radeon_noop_Install( ctx );
984 }
985
986
987 /*@}*/
988
989