1 /**************************************************************************
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
30 * Keith Whitwell <keith@tungstengraphics.com>
33 #include "draw_private.h"
34 #include "draw_context.h"
44 static unsigned reduced_prim
[PIPE_PRIM_POLYGON
+ 1] = {
58 static void draw_prim_queue_flush( struct draw_context
*draw
)
60 struct draw_stage
*first
= draw
->pipeline
.first
;
64 fprintf(stdout
,"Flushing with %d prims, %d verts\n",
65 draw
->pq
.queue_nr
, draw
->vs
.queue_nr
);
67 /* Make sure all vertices are available/shaded:
69 if (draw
->vs
.queue_nr
)
70 draw_vertex_shader_queue_flush(draw
);
72 switch (draw
->reduced_prim
) {
74 for (i
= 0; i
< draw
->pq
.queue_nr
; i
++) {
75 if (draw
->pq
.queue
[i
].reset_line_stipple
)
76 first
->reset_stipple_counter( first
);
78 first
->tri( first
, &draw
->pq
.queue
[i
] );
82 for (i
= 0; i
< draw
->pq
.queue_nr
; i
++) {
83 if (draw
->pq
.queue
[i
].reset_line_stipple
)
84 first
->reset_stipple_counter( first
);
86 first
->line( first
, &draw
->pq
.queue
[i
] );
90 first
->reset_stipple_counter( first
);
91 for (i
= 0; i
< draw
->pq
.queue_nr
; i
++)
92 first
->point( first
, &draw
->pq
.queue
[i
] );
96 draw
->pq
.queue_nr
= 0;
97 draw_vertex_cache_unreference( draw
);
101 void draw_do_flush( struct draw_context
*draw
,
104 if ((flush
& (DRAW_FLUSH_PRIM_QUEUE
|
105 DRAW_FLUSH_VERTEX_CACHE_INVALIDATE
|
109 draw_prim_queue_flush(draw
);
112 if ((flush
& (DRAW_FLUSH_VERTEX_CACHE_INVALIDATE
|
116 draw_vertex_cache_invalidate(draw
);
119 if ((flush
& DRAW_FLUSH_DRAW
) &&
122 draw
->pipeline
.first
->end( draw
->pipeline
.first
);
123 draw
->drawing
= FALSE
;
125 draw
->pipeline
.first
= draw
->pipeline
.validate
;
132 /* Return a pointer to a freshly queued primitive header. Ensure that
133 * there is room in the vertex cache for a maximum of "nr_verts" new
134 * vertices. Flush primitive and/or vertex queues if necessary to
137 static struct prim_header
*get_queued_prim( struct draw_context
*draw
,
140 if (!draw_vertex_cache_check_space( draw
, nr_verts
)) {
141 // fprintf(stderr, "v");
142 draw_do_flush( draw
, DRAW_FLUSH_VERTEX_CACHE_INVALIDATE
);
144 else if (draw
->pq
.queue_nr
== PRIM_QUEUE_LENGTH
) {
145 // fprintf(stderr, "p");
146 draw_do_flush( draw
, DRAW_FLUSH_PRIM_QUEUE
);
149 assert(draw
->pq
.queue_nr
< PRIM_QUEUE_LENGTH
);
151 return &draw
->pq
.queue
[draw
->pq
.queue_nr
++];
157 * Add a point to the primitive queue.
158 * \param i0 index into user's vertex arrays
160 static void do_point( struct draw_context
*draw
,
163 struct prim_header
*prim
= get_queued_prim( draw
, 1 );
165 prim
->reset_line_stipple
= 0;
168 prim
->v
[0] = draw
->vcache
.get_vertex( draw
, i0
);
173 * Add a line to the primitive queue.
174 * \param i0 index into user's vertex arrays
175 * \param i1 index into user's vertex arrays
177 static void do_line( struct draw_context
*draw
,
178 boolean reset_stipple
,
182 struct prim_header
*prim
= get_queued_prim( draw
, 2 );
184 prim
->reset_line_stipple
= reset_stipple
;
187 prim
->v
[0] = draw
->vcache
.get_vertex( draw
, i0
);
188 prim
->v
[1] = draw
->vcache
.get_vertex( draw
, i1
);
192 * Add a triangle to the primitive queue.
194 static void do_triangle( struct draw_context
*draw
,
199 struct prim_header
*prim
= get_queued_prim( draw
, 3 );
201 prim
->reset_line_stipple
= 1;
202 prim
->edgeflags
= ~0;
204 prim
->v
[0] = draw
->vcache
.get_vertex( draw
, i0
);
205 prim
->v
[1] = draw
->vcache
.get_vertex( draw
, i1
);
206 prim
->v
[2] = draw
->vcache
.get_vertex( draw
, i2
);
209 static void do_ef_triangle( struct draw_context
*draw
,
210 boolean reset_stipple
,
216 struct prim_header
*prim
= get_queued_prim( draw
, 3 );
217 struct vertex_header
*v0
= draw
->vcache
.get_vertex( draw
, i0
);
218 struct vertex_header
*v1
= draw
->vcache
.get_vertex( draw
, i1
);
219 struct vertex_header
*v2
= draw
->vcache
.get_vertex( draw
, i2
);
221 prim
->reset_line_stipple
= reset_stipple
;
223 prim
->edgeflags
= ef_mask
& ((v0
->edgeflag
<< 0) |
224 (v1
->edgeflag
<< 1) |
225 (v2
->edgeflag
<< 2));
233 static void do_quad( struct draw_context
*draw
,
239 const unsigned omitEdge2
= ~(1 << 1);
240 const unsigned omitEdge3
= ~(1 << 2);
241 do_ef_triangle( draw
, 1, omitEdge2
, v0
, v1
, v3
);
242 do_ef_triangle( draw
, 0, omitEdge3
, v1
, v2
, v3
);
247 * Main entrypoint to draw some number of points/lines/triangles
250 draw_prim( struct draw_context
*draw
, unsigned start
, unsigned count
)
254 // _mesa_printf("%s (%d) %d/%d\n", __FUNCTION__, draw->prim, start, count );
256 switch (draw
->prim
) {
257 case PIPE_PRIM_POINTS
:
258 for (i
= 0; i
< count
; i
++) {
264 case PIPE_PRIM_LINES
:
265 for (i
= 0; i
+1 < count
; i
+= 2) {
273 case PIPE_PRIM_LINE_LOOP
:
275 for (i
= 1; i
< count
; i
++) {
277 i
== 1, /* XXX: only if vb not split */
289 case PIPE_PRIM_LINE_STRIP
:
291 for (i
= 1; i
< count
; i
++) {
300 case PIPE_PRIM_TRIANGLES
:
301 for (i
= 0; i
+2 < count
; i
+= 3) {
302 do_ef_triangle( draw
,
311 case PIPE_PRIM_TRIANGLE_STRIP
:
312 for (i
= 0; i
+2 < count
; i
++) {
328 case PIPE_PRIM_TRIANGLE_FAN
:
330 for (i
= 0; i
+2 < count
; i
++) {
340 case PIPE_PRIM_QUADS
:
341 for (i
= 0; i
+3 < count
; i
+= 4) {
350 case PIPE_PRIM_QUAD_STRIP
:
351 for (i
= 0; i
+3 < count
; i
+= 2) {
360 case PIPE_PRIM_POLYGON
:
362 unsigned ef_mask
= (1<<2) | (1<<0);
364 for (i
= 0; i
+2 < count
; i
++) {
369 do_ef_triangle( draw
,
389 draw_set_prim( struct draw_context
*draw
, unsigned prim
)
391 assert(prim
>= PIPE_PRIM_POINTS
);
392 assert(prim
<= PIPE_PRIM_POLYGON
);
394 if (reduced_prim
[prim
] != draw
->reduced_prim
) {
395 draw_do_flush( draw
, DRAW_FLUSH_PRIM_QUEUE
);
396 draw
->reduced_prim
= reduced_prim
[prim
];
407 * This is the main entrypoint into the drawing module.
408 * \param prim one of PIPE_PRIM_x
409 * \param start index of first vertex to draw
410 * \param count number of vertices to draw
413 draw_arrays(struct draw_context
*draw
, unsigned prim
,
414 unsigned start
, unsigned count
)
416 if (!draw
->drawing
) {
417 draw
->drawing
= TRUE
;
419 /* tell drawing pipeline we're beginning drawing */
420 draw
->pipeline
.first
->begin( draw
->pipeline
.first
);
423 if (draw
->prim
!= prim
) {
424 draw_set_prim( draw
, prim
);
427 /* drawing done here: */
428 draw_prim(draw
, start
, count
);