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 **************************************************************************/
29 * \brief Primitive rasterization/rendering (points, lines, triangles)
31 * \author Keith Whitwell <keith@tungstengraphics.com>
35 #include "lp_context.h"
36 #include "lp_prim_setup.h"
38 #include "lp_quad_pipe.h"
41 #include "draw/draw_context.h"
42 #include "draw/draw_private.h"
43 #include "draw/draw_vertex.h"
44 #include "pipe/p_shader_tokens.h"
45 #include "pipe/p_thread.h"
46 #include "util/u_math.h"
47 #include "util/u_memory.h"
57 float dx
; /**< X(v1) - X(v0), used only during setup */
58 float dy
; /**< Y(v1) - Y(v0), used only during setup */
59 float dxdy
; /**< dx/dy */
60 float sx
, sy
; /**< first sample point coord */
61 int lines
; /**< number of lines on this edge */
64 #if LP_NUM_QUAD_THREADS > 1
66 /* Set to 1 if you want other threads to be instantly
67 * notified of pending jobs.
69 #define INSTANT_NOTEMPTY_NOTIFY 0
73 struct setup_context
*setup
;
80 typedef void (* quad_job_routine
)( struct setup_context
*setup
, uint thread
, struct quad_job
*job
);
84 struct quad_header_input input
;
85 struct quad_header_inout inout
;
86 quad_job_routine routine
;
89 #define NUM_QUAD_JOBS 64
93 struct quad_job jobs
[NUM_QUAD_JOBS
];
97 pipe_condvar que_notfull_condvar
;
98 pipe_condvar que_notempty_condvar
;
101 pipe_condvar que_done_condvar
;
105 add_quad_job( struct quad_job_que
*que
, struct quad_header
*quad
, quad_job_routine routine
)
107 #if INSTANT_NOTEMPTY_NOTIFY
111 /* Wait for empty slot, see if the que is empty.
113 pipe_mutex_lock( que
->que_mutex
);
114 while ((que
->last
+ 1) % NUM_QUAD_JOBS
== que
->first
) {
115 #if !INSTANT_NOTEMPTY_NOTIFY
116 pipe_condvar_broadcast( que
->que_notempty_condvar
);
118 pipe_condvar_wait( que
->que_notfull_condvar
, que
->que_mutex
);
120 #if INSTANT_NOTEMPTY_NOTIFY
121 empty
= que
->last
== que
->first
;
124 pipe_mutex_unlock( que
->que_mutex
);
128 que
->jobs
[que
->last
].input
= quad
->input
;
129 que
->jobs
[que
->last
].inout
= quad
->inout
;
130 que
->jobs
[que
->last
].routine
= routine
;
131 que
->last
= (que
->last
+ 1) % NUM_QUAD_JOBS
;
133 #if INSTANT_NOTEMPTY_NOTIFY
134 /* If the que was empty, notify consumers there's a job to be done.
137 pipe_mutex_lock( que
->que_mutex
);
138 pipe_condvar_broadcast( que
->que_notempty_condvar
);
139 pipe_mutex_unlock( que
->que_mutex
);
147 * Triangle setup info (derived from draw_stage).
148 * Also used for line drawing (taking some liberties).
150 struct setup_context
{
151 struct llvmpipe_context
*llvmpipe
;
153 /* Vertices are just an array of floats making up each attribute in
154 * turn. Currently fixed at 4 floats, but should change in time.
155 * Codegen will help cope with this.
157 const float (*vmax
)[4];
158 const float (*vmid
)[4];
159 const float (*vmin
)[4];
160 const float (*vprovoke
)[4];
168 struct tgsi_interp_coef coef
[PIPE_MAX_SHADER_INPUTS
];
169 struct tgsi_interp_coef posCoef
; /* For Z, W */
170 struct quad_header quad
;
172 #if LP_NUM_QUAD_THREADS > 1
173 struct quad_job_que que
;
174 struct thread_info threads
[LP_NUM_QUAD_THREADS
];
178 int left
[2]; /**< [0] = row0, [1] = row1 */
184 uint numFragsEmitted
; /**< per primitive */
185 uint numFragsWritten
; /**< per primitive */
188 unsigned winding
; /* which winding to cull */
191 #if LP_NUM_QUAD_THREADS > 1
193 static PIPE_THREAD_ROUTINE( quad_thread
, param
)
195 struct thread_info
*info
= (struct thread_info
*) param
;
196 struct quad_job_que
*que
= &info
->setup
->que
;
202 /* Wait for an available job.
204 pipe_mutex_lock( que
->que_mutex
);
205 while (que
->last
== que
->first
)
206 pipe_condvar_wait( que
->que_notempty_condvar
, que
->que_mutex
);
208 /* See if the que is full.
210 full
= (que
->last
+ 1) % NUM_QUAD_JOBS
== que
->first
;
212 /* Take a job and remove it from que.
214 job
= que
->jobs
[que
->first
];
215 que
->first
= (que
->first
+ 1) % NUM_QUAD_JOBS
;
217 /* Notify the producer if the que is not full.
220 pipe_condvar_signal( que
->que_notfull_condvar
);
221 pipe_mutex_unlock( que
->que_mutex
);
223 job
.routine( info
->setup
, info
->id
, &job
);
225 /* Notify the producer if that's the last finished job.
227 pipe_mutex_lock( que
->que_mutex
);
229 if (que
->jobs_added
== que
->jobs_done
)
230 pipe_condvar_signal( que
->que_done_condvar
);
231 pipe_mutex_unlock( que
->que_mutex
);
237 #define WAIT_FOR_COMPLETION(setup) \
239 pipe_mutex_lock( setup->que.que_mutex );\
240 if (!INSTANT_NOTEMPTY_NOTIFY)\
241 pipe_condvar_broadcast( setup->que.que_notempty_condvar );\
242 while (setup->que.jobs_added != setup->que.jobs_done)\
243 pipe_condvar_wait( setup->que.que_done_condvar, setup->que.que_mutex );\
244 pipe_mutex_unlock( setup->que.que_mutex );\
249 #define WAIT_FOR_COMPLETION(setup) ((void) 0)
256 * Do triangle cull test using tri determinant (sign indicates orientation)
257 * \return true if triangle is to be culled.
259 static INLINE boolean
260 cull_tri(const struct setup_context
*setup
, float det
)
263 /* if (det < 0 then Z points toward camera and triangle is
264 * counter-clockwise winding.
266 unsigned winding
= (det
< 0) ? PIPE_WINDING_CCW
: PIPE_WINDING_CW
;
268 if ((winding
& setup
->winding
) == 0)
280 * Clip setup->quad against the scissor/surface bounds.
283 quad_clip( struct setup_context
*setup
, struct quad_header
*quad
)
285 const struct pipe_scissor_state
*cliprect
= &setup
->llvmpipe
->cliprect
;
286 const int minx
= (int) cliprect
->minx
;
287 const int maxx
= (int) cliprect
->maxx
;
288 const int miny
= (int) cliprect
->miny
;
289 const int maxy
= (int) cliprect
->maxy
;
291 if (quad
->input
.x0
>= maxx
||
292 quad
->input
.y0
>= maxy
||
293 quad
->input
.x0
+ 1 < minx
||
294 quad
->input
.y0
+ 1 < miny
) {
295 /* totally clipped */
296 quad
->inout
.mask
= 0x0;
299 if (quad
->input
.x0
< minx
)
300 quad
->inout
.mask
&= (MASK_BOTTOM_RIGHT
| MASK_TOP_RIGHT
);
301 if (quad
->input
.y0
< miny
)
302 quad
->inout
.mask
&= (MASK_BOTTOM_LEFT
| MASK_BOTTOM_RIGHT
);
303 if (quad
->input
.x0
== maxx
- 1)
304 quad
->inout
.mask
&= (MASK_BOTTOM_LEFT
| MASK_TOP_LEFT
);
305 if (quad
->input
.y0
== maxy
- 1)
306 quad
->inout
.mask
&= (MASK_TOP_LEFT
| MASK_TOP_RIGHT
);
311 * Emit a quad (pass to next stage) with clipping.
314 clip_emit_quad( struct setup_context
*setup
, struct quad_header
*quad
, uint thread
)
316 quad_clip( setup
, quad
);
317 if (quad
->inout
.mask
) {
318 struct llvmpipe_context
*lp
= setup
->llvmpipe
;
320 lp
->quad
[thread
].first
->run( lp
->quad
[thread
].first
, quad
);
324 #if LP_NUM_QUAD_THREADS > 1
327 clip_emit_quad_job( struct setup_context
*setup
, uint thread
, struct quad_job
*job
)
329 struct quad_header quad
;
331 quad
.input
= job
->input
;
332 quad
.inout
= job
->inout
;
333 quad
.coef
= setup
->quad
.coef
;
334 quad
.posCoef
= setup
->quad
.posCoef
;
335 quad
.nr_attrs
= setup
->quad
.nr_attrs
;
336 clip_emit_quad( setup
, &quad
, thread
);
339 #define CLIP_EMIT_QUAD(setup) add_quad_job( &setup->que, &setup->quad, clip_emit_quad_job )
343 #define CLIP_EMIT_QUAD(setup) clip_emit_quad( setup, &setup->quad, 0 )
348 * Emit a quad (pass to next stage). No clipping is done.
351 emit_quad( struct setup_context
*setup
, struct quad_header
*quad
, uint thread
)
353 struct llvmpipe_context
*lp
= setup
->llvmpipe
;
355 uint mask
= quad
->inout
.mask
;
359 if (mask
& 1) setup
->numFragsEmitted
++;
360 if (mask
& 2) setup
->numFragsEmitted
++;
361 if (mask
& 4) setup
->numFragsEmitted
++;
362 if (mask
& 8) setup
->numFragsEmitted
++;
364 lp
->quad
[thread
].first
->run( lp
->quad
[thread
].first
, quad
);
366 mask
= quad
->inout
.mask
;
367 if (mask
& 1) setup
->numFragsWritten
++;
368 if (mask
& 2) setup
->numFragsWritten
++;
369 if (mask
& 4) setup
->numFragsWritten
++;
370 if (mask
& 8) setup
->numFragsWritten
++;
374 #if LP_NUM_QUAD_THREADS > 1
377 emit_quad_job( struct setup_context
*setup
, uint thread
, struct quad_job
*job
)
379 struct quad_header quad
;
381 quad
.input
= job
->input
;
382 quad
.inout
= job
->inout
;
383 quad
.coef
= setup
->quad
.coef
;
384 quad
.posCoef
= setup
->quad
.posCoef
;
385 quad
.nr_attrs
= setup
->quad
.nr_attrs
;
386 emit_quad( setup
, &quad
, thread
);
389 #define EMIT_QUAD(setup,x,y,qmask) do {\
390 setup->quad.input.x0 = x;\
391 setup->quad.input.y0 = y;\
392 setup->quad.inout.mask = qmask;\
393 add_quad_job( &setup->que, &setup->quad, emit_quad_job );\
398 #define EMIT_QUAD(setup,x,y,qmask) do {\
399 setup->quad.input.x0 = x;\
400 setup->quad.input.y0 = y;\
401 setup->quad.inout.mask = qmask;\
402 emit_quad( setup, &setup->quad, 0 );\
408 * Given an X or Y coordinate, return the block/quad coordinate that it
411 static INLINE
int block( int x
)
418 * Render a horizontal span of quads
420 static void flush_spans( struct setup_context
*setup
)
423 const int xleft0
= setup
->span
.left
[0];
424 const int xleft1
= setup
->span
.left
[1];
425 const int xright0
= setup
->span
.right
[0];
426 const int xright1
= setup
->span
.right
[1];
428 int minleft
= block(MIN2(xleft0
, xleft1
));
429 int maxright
= MAX2(xright0
, xright1
);
432 for (x
= minleft
; x
< maxright
; x
+= step
) {
433 unsigned skip_left0
= CLAMP(xleft0
- x
, 0, step
);
434 unsigned skip_left1
= CLAMP(xleft1
- x
, 0, step
);
435 unsigned skip_right0
= CLAMP(x
+ step
- xright0
, 0, step
);
436 unsigned skip_right1
= CLAMP(x
+ step
- xright1
, 0, step
);
439 unsigned skipmask_left0
= (1U << skip_left0
) - 1U;
440 unsigned skipmask_left1
= (1U << skip_left1
) - 1U;
442 /* These calculations fail when step == 32 and skip_right == 0.
444 unsigned skipmask_right0
= ~0U << (unsigned)(step
- skip_right0
);
445 unsigned skipmask_right1
= ~0U << (unsigned)(step
- skip_right1
);
447 unsigned mask0
= ~skipmask_left0
& ~skipmask_right0
;
448 unsigned mask1
= ~skipmask_left1
& ~skipmask_right1
;
450 while (mask0
| mask1
) {
451 unsigned quadmask
= (mask0
& 3) | ((mask1
& 3) << 2);
453 EMIT_QUAD( setup
, lx
, setup
->span
.y
, quadmask
);
462 setup
->span
.right
[0] = 0;
463 setup
->span
.right
[1] = 0;
464 setup
->span
.left
[0] = 1000000; /* greater than right[0] */
465 setup
->span
.left
[1] = 1000000; /* greater than right[1] */
470 static void print_vertex(const struct setup_context
*setup
,
474 debug_printf(" Vertex: (%p)\n", v
);
475 for (i
= 0; i
< setup
->quad
.nr_attrs
; i
++) {
476 debug_printf(" %d: %f %f %f %f\n", i
,
477 v
[i
][0], v
[i
][1], v
[i
][2], v
[i
][3]);
478 if (util_is_inf_or_nan(v
[i
][0])) {
479 debug_printf(" NaN!\n");
486 * Sort the vertices from top to bottom order, setting up the triangle
487 * edge fields (ebot, emaj, etop).
488 * \return FALSE if coords are inf/nan (cull the tri), TRUE otherwise
490 static boolean
setup_sort_vertices( struct setup_context
*setup
,
492 const float (*v0
)[4],
493 const float (*v1
)[4],
494 const float (*v2
)[4] )
496 setup
->vprovoke
= v2
;
498 /* determine bottom to top order of vertices */
545 setup
->ebot
.dx
= setup
->vmid
[0][0] - setup
->vmin
[0][0];
546 setup
->ebot
.dy
= setup
->vmid
[0][1] - setup
->vmin
[0][1];
547 setup
->emaj
.dx
= setup
->vmax
[0][0] - setup
->vmin
[0][0];
548 setup
->emaj
.dy
= setup
->vmax
[0][1] - setup
->vmin
[0][1];
549 setup
->etop
.dx
= setup
->vmax
[0][0] - setup
->vmid
[0][0];
550 setup
->etop
.dy
= setup
->vmax
[0][1] - setup
->vmid
[0][1];
553 * Compute triangle's area. Use 1/area to compute partial
554 * derivatives of attributes later.
556 * The area will be the same as prim->det, but the sign may be
557 * different depending on how the vertices get sorted above.
559 * To determine whether the primitive is front or back facing we
560 * use the prim->det value because its sign is correct.
563 const float area
= (setup
->emaj
.dx
* setup
->ebot
.dy
-
564 setup
->ebot
.dx
* setup
->emaj
.dy
);
566 setup
->oneoverarea
= 1.0f
/ area
;
569 debug_printf("%s one-over-area %f area %f det %f\n",
570 __FUNCTION__, setup->oneoverarea, area, det );
572 if (util_is_inf_or_nan(setup
->oneoverarea
))
576 /* We need to know if this is a front or back-facing triangle for:
577 * - the GLSL gl_FrontFacing fragment attribute (bool)
578 * - two-sided stencil test
580 setup
->quad
.input
.facing
= (det
> 0.0) ^ (setup
->llvmpipe
->rasterizer
->front_winding
== PIPE_WINDING_CW
);
587 * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
588 * The value value comes from vertex[slot][i].
589 * The result will be put into setup->coef[slot].a0[i].
590 * \param slot which attribute slot
591 * \param i which component of the slot (0..3)
593 static void const_coeff( struct setup_context
*setup
,
594 struct tgsi_interp_coef
*coef
,
595 uint vertSlot
, uint i
)
602 /* need provoking vertex info!
604 coef
->a0
[i
] = setup
->vprovoke
[vertSlot
][i
];
609 * Compute a0, dadx and dady for a linearly interpolated coefficient,
612 static void tri_linear_coeff( struct setup_context
*setup
,
613 struct tgsi_interp_coef
*coef
,
614 uint vertSlot
, uint i
)
616 float botda
= setup
->vmid
[vertSlot
][i
] - setup
->vmin
[vertSlot
][i
];
617 float majda
= setup
->vmax
[vertSlot
][i
] - setup
->vmin
[vertSlot
][i
];
618 float a
= setup
->ebot
.dy
* majda
- botda
* setup
->emaj
.dy
;
619 float b
= setup
->emaj
.dx
* botda
- majda
* setup
->ebot
.dx
;
620 float dadx
= a
* setup
->oneoverarea
;
621 float dady
= b
* setup
->oneoverarea
;
625 coef
->dadx
[i
] = dadx
;
626 coef
->dady
[i
] = dady
;
628 /* calculate a0 as the value which would be sampled for the
629 * fragment at (0,0), taking into account that we want to sample at
630 * pixel centers, in other words (0.5, 0.5).
632 * this is neat but unfortunately not a good way to do things for
633 * triangles with very large values of dadx or dady as it will
634 * result in the subtraction and re-addition from a0 of a very
635 * large number, which means we'll end up loosing a lot of the
636 * fractional bits and precision from a0. the way to fix this is
637 * to define a0 as the sample at a pixel center somewhere near vmin
638 * instead - i'll switch to this later.
640 coef
->a0
[i
] = (setup
->vmin
[vertSlot
][i
] -
641 (dadx
* (setup
->vmin
[0][0] - 0.5f
) +
642 dady
* (setup
->vmin
[0][1] - 0.5f
)));
645 debug_printf("attr[%d].%c: %f dx:%f dy:%f\n",
647 setup->coef[slot].a0[i],
648 setup->coef[slot].dadx[i],
649 setup->coef[slot].dady[i]);
655 * Compute a0, dadx and dady for a perspective-corrected interpolant,
657 * We basically multiply the vertex value by 1/w before computing
658 * the plane coefficients (a0, dadx, dady).
659 * Later, when we compute the value at a particular fragment position we'll
660 * divide the interpolated value by the interpolated W at that fragment.
662 static void tri_persp_coeff( struct setup_context
*setup
,
663 struct tgsi_interp_coef
*coef
,
664 uint vertSlot
, uint i
)
666 /* premultiply by 1/w (v[0][3] is always W):
668 float mina
= setup
->vmin
[vertSlot
][i
] * setup
->vmin
[0][3];
669 float mida
= setup
->vmid
[vertSlot
][i
] * setup
->vmid
[0][3];
670 float maxa
= setup
->vmax
[vertSlot
][i
] * setup
->vmax
[0][3];
671 float botda
= mida
- mina
;
672 float majda
= maxa
- mina
;
673 float a
= setup
->ebot
.dy
* majda
- botda
* setup
->emaj
.dy
;
674 float b
= setup
->emaj
.dx
* botda
- majda
* setup
->ebot
.dx
;
675 float dadx
= a
* setup
->oneoverarea
;
676 float dady
= b
* setup
->oneoverarea
;
679 debug_printf("tri persp %d,%d: %f %f %f\n", vertSlot, i,
680 setup->vmin[vertSlot][i],
681 setup->vmid[vertSlot][i],
682 setup->vmax[vertSlot][i]
687 coef
->dadx
[i
] = dadx
;
688 coef
->dady
[i
] = dady
;
689 coef
->a0
[i
] = (mina
-
690 (dadx
* (setup
->vmin
[0][0] - 0.5f
) +
691 dady
* (setup
->vmin
[0][1] - 0.5f
)));
696 * Special coefficient setup for gl_FragCoord.
697 * X and Y are trivial, though Y has to be inverted for OpenGL.
698 * Z and W are copied from posCoef which should have already been computed.
699 * We could do a bit less work if we'd examine gl_FragCoord's swizzle mask.
702 setup_fragcoord_coeff(struct setup_context
*setup
, uint slot
)
705 setup
->coef
[slot
].a0
[0] = 0;
706 setup
->coef
[slot
].dadx
[0] = 1.0;
707 setup
->coef
[slot
].dady
[0] = 0.0;
709 setup
->coef
[slot
].a0
[1] = 0.0;
710 setup
->coef
[slot
].dadx
[1] = 0.0;
711 setup
->coef
[slot
].dady
[1] = 1.0;
713 setup
->coef
[slot
].a0
[2] = setup
->posCoef
.a0
[2];
714 setup
->coef
[slot
].dadx
[2] = setup
->posCoef
.dadx
[2];
715 setup
->coef
[slot
].dady
[2] = setup
->posCoef
.dady
[2];
717 setup
->coef
[slot
].a0
[3] = setup
->posCoef
.a0
[3];
718 setup
->coef
[slot
].dadx
[3] = setup
->posCoef
.dadx
[3];
719 setup
->coef
[slot
].dady
[3] = setup
->posCoef
.dady
[3];
725 * Compute the setup->coef[] array dadx, dady, a0 values.
726 * Must be called after setup->vmin,vmid,vmax,vprovoke are initialized.
728 static void setup_tri_coefficients( struct setup_context
*setup
)
730 struct llvmpipe_context
*llvmpipe
= setup
->llvmpipe
;
731 const struct lp_fragment_shader
*lpfs
= llvmpipe
->fs
;
732 const struct vertex_info
*vinfo
= llvmpipe_get_vertex_info(llvmpipe
);
735 /* z and w are done by linear interpolation:
737 tri_linear_coeff(setup
, &setup
->posCoef
, 0, 2);
738 tri_linear_coeff(setup
, &setup
->posCoef
, 0, 3);
740 /* setup interpolation for all the remaining attributes:
742 for (fragSlot
= 0; fragSlot
< lpfs
->info
.num_inputs
; fragSlot
++) {
743 const uint vertSlot
= vinfo
->attrib
[fragSlot
].src_index
;
746 switch (vinfo
->attrib
[fragSlot
].interp_mode
) {
747 case INTERP_CONSTANT
:
748 for (j
= 0; j
< NUM_CHANNELS
; j
++)
749 const_coeff(setup
, &setup
->coef
[fragSlot
], vertSlot
, j
);
752 for (j
= 0; j
< NUM_CHANNELS
; j
++)
753 tri_linear_coeff(setup
, &setup
->coef
[fragSlot
], vertSlot
, j
);
755 case INTERP_PERSPECTIVE
:
756 for (j
= 0; j
< NUM_CHANNELS
; j
++)
757 tri_persp_coeff(setup
, &setup
->coef
[fragSlot
], vertSlot
, j
);
760 setup_fragcoord_coeff(setup
, fragSlot
);
766 if (lpfs
->info
.input_semantic_name
[fragSlot
] == TGSI_SEMANTIC_FACE
) {
767 setup
->coef
[fragSlot
].a0
[0] = 1.0f
- setup
->quad
.input
.facing
;
768 setup
->coef
[fragSlot
].dadx
[0] = 0.0;
769 setup
->coef
[fragSlot
].dady
[0] = 0.0;
776 static void setup_tri_edges( struct setup_context
*setup
)
778 float vmin_x
= setup
->vmin
[0][0] + 0.5f
;
779 float vmid_x
= setup
->vmid
[0][0] + 0.5f
;
781 float vmin_y
= setup
->vmin
[0][1] - 0.5f
;
782 float vmid_y
= setup
->vmid
[0][1] - 0.5f
;
783 float vmax_y
= setup
->vmax
[0][1] - 0.5f
;
785 setup
->emaj
.sy
= ceilf(vmin_y
);
786 setup
->emaj
.lines
= (int) ceilf(vmax_y
- setup
->emaj
.sy
);
787 setup
->emaj
.dxdy
= setup
->emaj
.dx
/ setup
->emaj
.dy
;
788 setup
->emaj
.sx
= vmin_x
+ (setup
->emaj
.sy
- vmin_y
) * setup
->emaj
.dxdy
;
790 setup
->etop
.sy
= ceilf(vmid_y
);
791 setup
->etop
.lines
= (int) ceilf(vmax_y
- setup
->etop
.sy
);
792 setup
->etop
.dxdy
= setup
->etop
.dx
/ setup
->etop
.dy
;
793 setup
->etop
.sx
= vmid_x
+ (setup
->etop
.sy
- vmid_y
) * setup
->etop
.dxdy
;
795 setup
->ebot
.sy
= ceilf(vmin_y
);
796 setup
->ebot
.lines
= (int) ceilf(vmid_y
- setup
->ebot
.sy
);
797 setup
->ebot
.dxdy
= setup
->ebot
.dx
/ setup
->ebot
.dy
;
798 setup
->ebot
.sx
= vmin_x
+ (setup
->ebot
.sy
- vmin_y
) * setup
->ebot
.dxdy
;
803 * Render the upper or lower half of a triangle.
804 * Scissoring/cliprect is applied here too.
806 static void subtriangle( struct setup_context
*setup
,
811 const struct pipe_scissor_state
*cliprect
= &setup
->llvmpipe
->cliprect
;
812 const int minx
= (int) cliprect
->minx
;
813 const int maxx
= (int) cliprect
->maxx
;
814 const int miny
= (int) cliprect
->miny
;
815 const int maxy
= (int) cliprect
->maxy
;
816 int y
, start_y
, finish_y
;
817 int sy
= (int)eleft
->sy
;
819 assert((int)eleft
->sy
== (int) eright
->sy
);
821 /* clip top/bottom */
826 finish_y
= sy
+ lines
;
834 debug_printf("%s %d %d\n", __FUNCTION__, start_y, finish_y);
837 for (y
= start_y
; y
< finish_y
; y
++) {
839 /* avoid accumulating adds as floats don't have the precision to
840 * accurately iterate large triangle edges that way. luckily we
841 * can just multiply these days.
843 * this is all drowned out by the attribute interpolation anyway.
845 int left
= (int)(eleft
->sx
+ y
* eleft
->dxdy
);
846 int right
= (int)(eright
->sx
+ y
* eright
->dxdy
);
848 /* clip left/right */
856 if (block(_y
) != setup
->span
.y
) {
858 setup
->span
.y
= block(_y
);
861 setup
->span
.left
[_y
&1] = left
;
862 setup
->span
.right
[_y
&1] = right
;
867 /* save the values so that emaj can be restarted:
869 eleft
->sx
+= lines
* eleft
->dxdy
;
870 eright
->sx
+= lines
* eright
->dxdy
;
877 * Recalculate prim's determinant. This is needed as we don't have
878 * get this information through the vbuf_render interface & we must
882 calc_det( const float (*v0
)[4],
883 const float (*v1
)[4],
884 const float (*v2
)[4] )
886 /* edge vectors e = v0 - v2, f = v1 - v2 */
887 const float ex
= v0
[0][0] - v2
[0][0];
888 const float ey
= v0
[0][1] - v2
[0][1];
889 const float fx
= v1
[0][0] - v2
[0][0];
890 const float fy
= v1
[0][1] - v2
[0][1];
892 /* det = cross(e,f).z */
893 return ex
* fy
- ey
* fx
;
898 * Do setup for triangle rasterization, then render the triangle.
900 void setup_tri( struct setup_context
*setup
,
901 const float (*v0
)[4],
902 const float (*v1
)[4],
903 const float (*v2
)[4] )
908 debug_printf("Setup triangle:\n");
909 print_vertex(setup
, v0
);
910 print_vertex(setup
, v1
);
911 print_vertex(setup
, v2
);
914 if (setup
->llvmpipe
->no_rast
)
917 det
= calc_det(v0
, v1
, v2
);
919 debug_printf("%s\n", __FUNCTION__ );
923 setup
->numFragsEmitted
= 0;
924 setup
->numFragsWritten
= 0;
927 if (cull_tri( setup
, det
))
930 if (!setup_sort_vertices( setup
, det
, v0
, v1
, v2
))
932 setup_tri_coefficients( setup
);
933 setup_tri_edges( setup
);
935 setup
->quad
.input
.prim
= QUAD_PRIM_TRI
;
938 setup
->span
.right
[0] = 0;
939 setup
->span
.right
[1] = 0;
940 /* setup->span.z_mode = tri_z_mode( setup->ctx ); */
942 /* init_constant_attribs( setup ); */
944 if (setup
->oneoverarea
< 0.0) {
947 subtriangle( setup
, &setup
->emaj
, &setup
->ebot
, setup
->ebot
.lines
);
948 subtriangle( setup
, &setup
->emaj
, &setup
->etop
, setup
->etop
.lines
);
953 subtriangle( setup
, &setup
->ebot
, &setup
->emaj
, setup
->ebot
.lines
);
954 subtriangle( setup
, &setup
->etop
, &setup
->emaj
, setup
->etop
.lines
);
957 flush_spans( setup
);
959 WAIT_FOR_COMPLETION(setup
);
962 printf("Tri: %u frags emitted, %u written\n",
963 setup
->numFragsEmitted
,
964 setup
->numFragsWritten
);
971 * Compute a0, dadx and dady for a linearly interpolated coefficient,
975 line_linear_coeff(const struct setup_context
*setup
,
976 struct tgsi_interp_coef
*coef
,
977 uint vertSlot
, uint i
)
979 const float da
= setup
->vmax
[vertSlot
][i
] - setup
->vmin
[vertSlot
][i
];
980 const float dadx
= da
* setup
->emaj
.dx
* setup
->oneoverarea
;
981 const float dady
= da
* setup
->emaj
.dy
* setup
->oneoverarea
;
982 coef
->dadx
[i
] = dadx
;
983 coef
->dady
[i
] = dady
;
984 coef
->a0
[i
] = (setup
->vmin
[vertSlot
][i
] -
985 (dadx
* (setup
->vmin
[0][0] - 0.5f
) +
986 dady
* (setup
->vmin
[0][1] - 0.5f
)));
991 * Compute a0, dadx and dady for a perspective-corrected interpolant,
995 line_persp_coeff(const struct setup_context
*setup
,
996 struct tgsi_interp_coef
*coef
,
997 uint vertSlot
, uint i
)
999 /* XXX double-check/verify this arithmetic */
1000 const float a0
= setup
->vmin
[vertSlot
][i
] * setup
->vmin
[0][3];
1001 const float a1
= setup
->vmax
[vertSlot
][i
] * setup
->vmax
[0][3];
1002 const float da
= a1
- a0
;
1003 const float dadx
= da
* setup
->emaj
.dx
* setup
->oneoverarea
;
1004 const float dady
= da
* setup
->emaj
.dy
* setup
->oneoverarea
;
1005 coef
->dadx
[i
] = dadx
;
1006 coef
->dady
[i
] = dady
;
1007 coef
->a0
[i
] = (setup
->vmin
[vertSlot
][i
] -
1008 (dadx
* (setup
->vmin
[0][0] - 0.5f
) +
1009 dady
* (setup
->vmin
[0][1] - 0.5f
)));
1014 * Compute the setup->coef[] array dadx, dady, a0 values.
1015 * Must be called after setup->vmin,vmax are initialized.
1017 static INLINE boolean
1018 setup_line_coefficients(struct setup_context
*setup
,
1019 const float (*v0
)[4],
1020 const float (*v1
)[4])
1022 struct llvmpipe_context
*llvmpipe
= setup
->llvmpipe
;
1023 const struct lp_fragment_shader
*lpfs
= llvmpipe
->fs
;
1024 const struct vertex_info
*vinfo
= llvmpipe_get_vertex_info(llvmpipe
);
1028 /* use setup->vmin, vmax to point to vertices */
1029 if (llvmpipe
->rasterizer
->flatshade_first
)
1030 setup
->vprovoke
= v0
;
1032 setup
->vprovoke
= v1
;
1036 setup
->emaj
.dx
= setup
->vmax
[0][0] - setup
->vmin
[0][0];
1037 setup
->emaj
.dy
= setup
->vmax
[0][1] - setup
->vmin
[0][1];
1039 /* NOTE: this is not really area but something proportional to it */
1040 area
= setup
->emaj
.dx
* setup
->emaj
.dx
+ setup
->emaj
.dy
* setup
->emaj
.dy
;
1041 if (area
== 0.0f
|| util_is_inf_or_nan(area
))
1043 setup
->oneoverarea
= 1.0f
/ area
;
1045 /* z and w are done by linear interpolation:
1047 line_linear_coeff(setup
, &setup
->posCoef
, 0, 2);
1048 line_linear_coeff(setup
, &setup
->posCoef
, 0, 3);
1050 /* setup interpolation for all the remaining attributes:
1052 for (fragSlot
= 0; fragSlot
< lpfs
->info
.num_inputs
; fragSlot
++) {
1053 const uint vertSlot
= vinfo
->attrib
[fragSlot
].src_index
;
1056 switch (vinfo
->attrib
[fragSlot
].interp_mode
) {
1057 case INTERP_CONSTANT
:
1058 for (j
= 0; j
< NUM_CHANNELS
; j
++)
1059 const_coeff(setup
, &setup
->coef
[fragSlot
], vertSlot
, j
);
1062 for (j
= 0; j
< NUM_CHANNELS
; j
++)
1063 line_linear_coeff(setup
, &setup
->coef
[fragSlot
], vertSlot
, j
);
1065 case INTERP_PERSPECTIVE
:
1066 for (j
= 0; j
< NUM_CHANNELS
; j
++)
1067 line_persp_coeff(setup
, &setup
->coef
[fragSlot
], vertSlot
, j
);
1070 setup_fragcoord_coeff(setup
, fragSlot
);
1076 if (lpfs
->info
.input_semantic_name
[fragSlot
] == TGSI_SEMANTIC_FACE
) {
1077 setup
->coef
[fragSlot
].a0
[0] = 1.0f
- setup
->quad
.input
.facing
;
1078 setup
->coef
[fragSlot
].dadx
[0] = 0.0;
1079 setup
->coef
[fragSlot
].dady
[0] = 0.0;
1087 * Plot a pixel in a line segment.
1090 plot(struct setup_context
*setup
, int x
, int y
)
1092 const int iy
= y
& 1;
1093 const int ix
= x
& 1;
1094 const int quadX
= x
- ix
;
1095 const int quadY
= y
- iy
;
1096 const int mask
= (1 << ix
) << (2 * iy
);
1098 if (quadX
!= setup
->quad
.input
.x0
||
1099 quadY
!= setup
->quad
.input
.y0
)
1101 /* flush prev quad, start new quad */
1103 if (setup
->quad
.input
.x0
!= -1)
1104 CLIP_EMIT_QUAD(setup
);
1106 setup
->quad
.input
.x0
= quadX
;
1107 setup
->quad
.input
.y0
= quadY
;
1108 setup
->quad
.inout
.mask
= 0x0;
1111 setup
->quad
.inout
.mask
|= mask
;
1116 * Do setup for line rasterization, then render the line.
1117 * Single-pixel width, no stipple, etc. We rely on the 'draw' module
1118 * to handle stippling and wide lines.
1121 setup_line(struct setup_context
*setup
,
1122 const float (*v0
)[4],
1123 const float (*v1
)[4])
1125 int x0
= (int) v0
[0][0];
1126 int x1
= (int) v1
[0][0];
1127 int y0
= (int) v0
[0][1];
1128 int y1
= (int) v1
[0][1];
1134 debug_printf("Setup line:\n");
1135 print_vertex(setup
, v0
);
1136 print_vertex(setup
, v1
);
1139 if (setup
->llvmpipe
->no_rast
)
1142 if (dx
== 0 && dy
== 0)
1145 if (!setup_line_coefficients(setup
, v0
, v1
))
1148 assert(v0
[0][0] < 1.0e9
);
1149 assert(v0
[0][1] < 1.0e9
);
1150 assert(v1
[0][0] < 1.0e9
);
1151 assert(v1
[0][1] < 1.0e9
);
1154 dx
= -dx
; /* make positive */
1162 dy
= -dy
; /* make positive */
1172 setup
->quad
.input
.x0
= setup
->quad
.input
.y0
= -1;
1173 setup
->quad
.inout
.mask
= 0x0;
1174 setup
->quad
.input
.prim
= QUAD_PRIM_LINE
;
1175 /* XXX temporary: set coverage to 1.0 so the line appears
1176 * if AA mode happens to be enabled.
1178 setup
->quad
.input
.coverage
[0] =
1179 setup
->quad
.input
.coverage
[1] =
1180 setup
->quad
.input
.coverage
[2] =
1181 setup
->quad
.input
.coverage
[3] = 1.0;
1184 /*** X-major line ***/
1186 const int errorInc
= dy
+ dy
;
1187 int error
= errorInc
- dx
;
1188 const int errorDec
= error
- dx
;
1190 for (i
= 0; i
< dx
; i
++) {
1191 plot(setup
, x0
, y0
);
1204 /*** Y-major line ***/
1206 const int errorInc
= dx
+ dx
;
1207 int error
= errorInc
- dy
;
1208 const int errorDec
= error
- dy
;
1210 for (i
= 0; i
< dy
; i
++) {
1211 plot(setup
, x0
, y0
);
1224 /* draw final quad */
1225 if (setup
->quad
.inout
.mask
) {
1226 CLIP_EMIT_QUAD(setup
);
1229 WAIT_FOR_COMPLETION(setup
);
1234 point_persp_coeff(const struct setup_context
*setup
,
1235 const float (*vert
)[4],
1236 struct tgsi_interp_coef
*coef
,
1237 uint vertSlot
, uint i
)
1240 coef
->dadx
[i
] = 0.0F
;
1241 coef
->dady
[i
] = 0.0F
;
1242 coef
->a0
[i
] = vert
[vertSlot
][i
] * vert
[0][3];
1247 * Do setup for point rasterization, then render the point.
1248 * Round or square points...
1249 * XXX could optimize a lot for 1-pixel points.
1252 setup_point( struct setup_context
*setup
,
1253 const float (*v0
)[4] )
1255 struct llvmpipe_context
*llvmpipe
= setup
->llvmpipe
;
1256 const struct lp_fragment_shader
*lpfs
= llvmpipe
->fs
;
1257 const int sizeAttr
= setup
->llvmpipe
->psize_slot
;
1259 = sizeAttr
> 0 ? v0
[sizeAttr
][0]
1260 : setup
->llvmpipe
->rasterizer
->point_size
;
1261 const float halfSize
= 0.5F
* size
;
1262 const boolean round
= (boolean
) setup
->llvmpipe
->rasterizer
->point_smooth
;
1263 const float x
= v0
[0][0]; /* Note: data[0] is always position */
1264 const float y
= v0
[0][1];
1265 const struct vertex_info
*vinfo
= llvmpipe_get_vertex_info(llvmpipe
);
1269 debug_printf("Setup point:\n");
1270 print_vertex(setup
, v0
);
1273 if (llvmpipe
->no_rast
)
1276 /* For points, all interpolants are constant-valued.
1277 * However, for point sprites, we'll need to setup texcoords appropriately.
1278 * XXX: which coefficients are the texcoords???
1279 * We may do point sprites as textured quads...
1281 * KW: We don't know which coefficients are texcoords - ultimately
1282 * the choice of what interpolation mode to use for each attribute
1283 * should be determined by the fragment program, using
1284 * per-attribute declaration statements that include interpolation
1285 * mode as a parameter. So either the fragment program will have
1286 * to be adjusted for pointsprite vs normal point behaviour, or
1287 * otherwise a special interpolation mode will have to be defined
1288 * which matches the required behaviour for point sprites. But -
1289 * the latter is not a feature of normal hardware, and as such
1290 * probably should be ruled out on that basis.
1292 setup
->vprovoke
= v0
;
1295 const_coeff(setup
, &setup
->posCoef
, 0, 2);
1296 const_coeff(setup
, &setup
->posCoef
, 0, 3);
1298 for (fragSlot
= 0; fragSlot
< lpfs
->info
.num_inputs
; fragSlot
++) {
1299 const uint vertSlot
= vinfo
->attrib
[fragSlot
].src_index
;
1302 switch (vinfo
->attrib
[fragSlot
].interp_mode
) {
1303 case INTERP_CONSTANT
:
1306 for (j
= 0; j
< NUM_CHANNELS
; j
++)
1307 const_coeff(setup
, &setup
->coef
[fragSlot
], vertSlot
, j
);
1309 case INTERP_PERSPECTIVE
:
1310 for (j
= 0; j
< NUM_CHANNELS
; j
++)
1311 point_persp_coeff(setup
, setup
->vprovoke
,
1312 &setup
->coef
[fragSlot
], vertSlot
, j
);
1315 setup_fragcoord_coeff(setup
, fragSlot
);
1321 if (lpfs
->info
.input_semantic_name
[fragSlot
] == TGSI_SEMANTIC_FACE
) {
1322 setup
->coef
[fragSlot
].a0
[0] = 1.0f
- setup
->quad
.input
.facing
;
1323 setup
->coef
[fragSlot
].dadx
[0] = 0.0;
1324 setup
->coef
[fragSlot
].dady
[0] = 0.0;
1328 setup
->quad
.input
.prim
= QUAD_PRIM_POINT
;
1330 if (halfSize
<= 0.5 && !round
) {
1331 /* special case for 1-pixel points */
1332 const int ix
= ((int) x
) & 1;
1333 const int iy
= ((int) y
) & 1;
1334 setup
->quad
.input
.x0
= (int) x
- ix
;
1335 setup
->quad
.input
.y0
= (int) y
- iy
;
1336 setup
->quad
.inout
.mask
= (1 << ix
) << (2 * iy
);
1337 CLIP_EMIT_QUAD(setup
);
1341 /* rounded points */
1342 const int ixmin
= block((int) (x
- halfSize
));
1343 const int ixmax
= block((int) (x
+ halfSize
));
1344 const int iymin
= block((int) (y
- halfSize
));
1345 const int iymax
= block((int) (y
+ halfSize
));
1346 const float rmin
= halfSize
- 0.7071F
; /* 0.7071 = sqrt(2)/2 */
1347 const float rmax
= halfSize
+ 0.7071F
;
1348 const float rmin2
= MAX2(0.0F
, rmin
* rmin
);
1349 const float rmax2
= rmax
* rmax
;
1350 const float cscale
= 1.0F
/ (rmax2
- rmin2
);
1353 for (iy
= iymin
; iy
<= iymax
; iy
+= 2) {
1354 for (ix
= ixmin
; ix
<= ixmax
; ix
+= 2) {
1355 float dx
, dy
, dist2
, cover
;
1357 setup
->quad
.inout
.mask
= 0x0;
1359 dx
= (ix
+ 0.5f
) - x
;
1360 dy
= (iy
+ 0.5f
) - y
;
1361 dist2
= dx
* dx
+ dy
* dy
;
1362 if (dist2
<= rmax2
) {
1363 cover
= 1.0F
- (dist2
- rmin2
) * cscale
;
1364 setup
->quad
.input
.coverage
[QUAD_TOP_LEFT
] = MIN2(cover
, 1.0f
);
1365 setup
->quad
.inout
.mask
|= MASK_TOP_LEFT
;
1368 dx
= (ix
+ 1.5f
) - x
;
1369 dy
= (iy
+ 0.5f
) - y
;
1370 dist2
= dx
* dx
+ dy
* dy
;
1371 if (dist2
<= rmax2
) {
1372 cover
= 1.0F
- (dist2
- rmin2
) * cscale
;
1373 setup
->quad
.input
.coverage
[QUAD_TOP_RIGHT
] = MIN2(cover
, 1.0f
);
1374 setup
->quad
.inout
.mask
|= MASK_TOP_RIGHT
;
1377 dx
= (ix
+ 0.5f
) - x
;
1378 dy
= (iy
+ 1.5f
) - y
;
1379 dist2
= dx
* dx
+ dy
* dy
;
1380 if (dist2
<= rmax2
) {
1381 cover
= 1.0F
- (dist2
- rmin2
) * cscale
;
1382 setup
->quad
.input
.coverage
[QUAD_BOTTOM_LEFT
] = MIN2(cover
, 1.0f
);
1383 setup
->quad
.inout
.mask
|= MASK_BOTTOM_LEFT
;
1386 dx
= (ix
+ 1.5f
) - x
;
1387 dy
= (iy
+ 1.5f
) - y
;
1388 dist2
= dx
* dx
+ dy
* dy
;
1389 if (dist2
<= rmax2
) {
1390 cover
= 1.0F
- (dist2
- rmin2
) * cscale
;
1391 setup
->quad
.input
.coverage
[QUAD_BOTTOM_RIGHT
] = MIN2(cover
, 1.0f
);
1392 setup
->quad
.inout
.mask
|= MASK_BOTTOM_RIGHT
;
1395 if (setup
->quad
.inout
.mask
) {
1396 setup
->quad
.input
.x0
= ix
;
1397 setup
->quad
.input
.y0
= iy
;
1398 CLIP_EMIT_QUAD(setup
);
1405 const int xmin
= (int) (x
+ 0.75 - halfSize
);
1406 const int ymin
= (int) (y
+ 0.25 - halfSize
);
1407 const int xmax
= xmin
+ (int) size
;
1408 const int ymax
= ymin
+ (int) size
;
1409 /* XXX could apply scissor to xmin,ymin,xmax,ymax now */
1410 const int ixmin
= block(xmin
);
1411 const int ixmax
= block(xmax
- 1);
1412 const int iymin
= block(ymin
);
1413 const int iymax
= block(ymax
- 1);
1417 debug_printf("(%f, %f) -> X:%d..%d Y:%d..%d\n", x, y, xmin, xmax,ymin,ymax);
1419 for (iy
= iymin
; iy
<= iymax
; iy
+= 2) {
1422 /* above the top edge */
1423 rowMask
&= (MASK_BOTTOM_LEFT
| MASK_BOTTOM_RIGHT
);
1425 if (iy
+ 1 >= ymax
) {
1426 /* below the bottom edge */
1427 rowMask
&= (MASK_TOP_LEFT
| MASK_TOP_RIGHT
);
1430 for (ix
= ixmin
; ix
<= ixmax
; ix
+= 2) {
1431 uint mask
= rowMask
;
1434 /* fragment is past left edge of point, turn off left bits */
1435 mask
&= (MASK_BOTTOM_RIGHT
| MASK_TOP_RIGHT
);
1437 if (ix
+ 1 >= xmax
) {
1438 /* past the right edge */
1439 mask
&= (MASK_BOTTOM_LEFT
| MASK_TOP_LEFT
);
1442 setup
->quad
.inout
.mask
= mask
;
1443 setup
->quad
.input
.x0
= ix
;
1444 setup
->quad
.input
.y0
= iy
;
1445 CLIP_EMIT_QUAD(setup
);
1451 WAIT_FOR_COMPLETION(setup
);
1454 void setup_prepare( struct setup_context
*setup
)
1456 struct llvmpipe_context
*lp
= setup
->llvmpipe
;
1460 llvmpipe_update_derived(lp
);
1463 /* Note: nr_attrs is only used for debugging (vertex printing) */
1464 setup
->quad
.nr_attrs
= draw_num_vs_outputs(lp
->draw
);
1466 for (i
= 0; i
< LP_NUM_QUAD_THREADS
; i
++) {
1467 lp
->quad
[i
].first
->begin( lp
->quad
[i
].first
);
1470 if (lp
->reduced_api_prim
== PIPE_PRIM_TRIANGLES
&&
1471 lp
->rasterizer
->fill_cw
== PIPE_POLYGON_MODE_FILL
&&
1472 lp
->rasterizer
->fill_ccw
== PIPE_POLYGON_MODE_FILL
) {
1473 /* we'll do culling */
1474 setup
->winding
= lp
->rasterizer
->cull_mode
;
1477 /* 'draw' will do culling */
1478 setup
->winding
= PIPE_WINDING_NONE
;
1484 void setup_destroy_context( struct setup_context
*setup
)
1491 * Create a new primitive setup/render stage.
1493 struct setup_context
*setup_create_context( struct llvmpipe_context
*llvmpipe
)
1495 struct setup_context
*setup
= CALLOC_STRUCT(setup_context
);
1496 #if LP_NUM_QUAD_THREADS > 1
1500 setup
->llvmpipe
= llvmpipe
;
1502 setup
->quad
.coef
= setup
->coef
;
1503 setup
->quad
.posCoef
= &setup
->posCoef
;
1505 setup
->span
.left
[0] = 1000000; /* greater than right[0] */
1506 setup
->span
.left
[1] = 1000000; /* greater than right[1] */
1508 #if LP_NUM_QUAD_THREADS > 1
1509 setup
->que
.first
= 0;
1510 setup
->que
.last
= 0;
1511 pipe_mutex_init( setup
->que
.que_mutex
);
1512 pipe_condvar_init( setup
->que
.que_notfull_condvar
);
1513 pipe_condvar_init( setup
->que
.que_notempty_condvar
);
1514 setup
->que
.jobs_added
= 0;
1515 setup
->que
.jobs_done
= 0;
1516 pipe_condvar_init( setup
->que
.que_done_condvar
);
1517 for (i
= 0; i
< LP_NUM_QUAD_THREADS
; i
++) {
1518 setup
->threads
[i
].setup
= setup
;
1519 setup
->threads
[i
].id
= i
;
1520 setup
->threads
[i
].handle
= pipe_thread_create( quad_thread
, &setup
->threads
[i
] );