sp_setup.c

Go to the documentation of this file.
00001 /**************************************************************************
00002  *
00003  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
00004  * All Rights Reserved.
00005  *
00006  * Permission is hereby granted, free of charge, to any person obtaining a
00007  * copy of this software and associated documentation files (the
00008  * "Software"), to deal in the Software without restriction, including
00009  * without limitation the rights to use, copy, modify, merge, publish,
00010  * distribute, sub license, and/or sell copies of the Software, and to
00011  * permit persons to whom the Software is furnished to do so, subject to
00012  * the following conditions:
00013  *
00014  * The above copyright notice and this permission notice (including the
00015  * next paragraph) shall be included in all copies or substantial portions
00016  * of the Software.
00017  *
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00019  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
00021  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
00022  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
00023  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
00024  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00025  *
00026  **************************************************************************/
00027 
00035 #include "sp_setup.h"
00036 
00037 #include "sp_context.h"
00038 #include "sp_headers.h"
00039 #include "sp_quad.h"
00040 #include "sp_state.h"
00041 #include "sp_prim_setup.h"
00042 #include "draw/draw_context.h"
00043 #include "draw/draw_private.h"
00044 #include "draw/draw_vertex.h"
00045 #include "pipe/p_shader_tokens.h"
00046 #include "pipe/p_thread.h"
00047 #include "util/u_math.h"
00048 #include "util/u_memory.h"
00049 
00050 
00051 #define DEBUG_VERTS 0
00052 #define DEBUG_FRAGS 0
00053 
00057 struct edge {
00058    float dx;            
00059    float dy;            
00060    float dxdy;          
00061    float sx, sy;        
00062    int lines;           
00063 };
00064 
00065 #if SP_NUM_QUAD_THREADS > 1
00066 
00067 /* Set to 1 if you want other threads to be instantly
00068  * notified of pending jobs.
00069  */
00070 #define INSTANT_NOTEMPTY_NOTIFY 0
00071 
00072 struct thread_info
00073 {
00074    struct setup_context *setup;
00075    uint id;
00076    pipe_thread handle;
00077 };
00078 
00079 struct quad_job;
00080 
00081 typedef void (* quad_job_routine)( struct setup_context *setup, uint thread, struct quad_job *job );
00082 
00083 struct quad_job
00084 {
00085    struct quad_header_input input;
00086    struct quad_header_inout inout;
00087    quad_job_routine routine;
00088 };
00089 
00090 #define NUM_QUAD_JOBS 64
00091 
00092 struct quad_job_que
00093 {
00094    struct quad_job jobs[NUM_QUAD_JOBS];
00095    uint first;
00096    uint last;
00097    pipe_mutex que_mutex;
00098    pipe_condvar que_notfull_condvar;
00099    pipe_condvar que_notempty_condvar;
00100    uint jobs_added;
00101    uint jobs_done;
00102    pipe_condvar que_done_condvar;
00103 };
00104 
00105 static void
00106 add_quad_job( struct quad_job_que *que, struct quad_header *quad, quad_job_routine routine )
00107 {
00108 #if INSTANT_NOTEMPTY_NOTIFY
00109    boolean empty;
00110 #endif
00111 
00112    /* Wait for empty slot, see if the que is empty.
00113     */
00114    pipe_mutex_lock( que->que_mutex );
00115    while ((que->last + 1) % NUM_QUAD_JOBS == que->first) {
00116 #if !INSTANT_NOTEMPTY_NOTIFY
00117       pipe_condvar_broadcast( que->que_notempty_condvar );
00118 #endif
00119       pipe_condvar_wait( que->que_notfull_condvar, que->que_mutex );
00120    }
00121 #if INSTANT_NOTEMPTY_NOTIFY
00122    empty = que->last == que->first;
00123 #endif
00124    que->jobs_added++;
00125    pipe_mutex_unlock( que->que_mutex );
00126 
00127    /* Submit new job.
00128     */
00129    que->jobs[que->last].input = quad->input;
00130    que->jobs[que->last].inout = quad->inout;
00131    que->jobs[que->last].routine = routine;
00132    que->last = (que->last + 1) % NUM_QUAD_JOBS;
00133 
00134 #if INSTANT_NOTEMPTY_NOTIFY
00135    /* If the que was empty, notify consumers there's a job to be done.
00136     */
00137    if (empty) {
00138       pipe_mutex_lock( que->que_mutex );
00139       pipe_condvar_broadcast( que->que_notempty_condvar );
00140       pipe_mutex_unlock( que->que_mutex );
00141    }
00142 #endif
00143 }
00144 
00145 #endif
00146 
00151 struct setup_context {
00152    struct softpipe_context *softpipe;
00153 
00154    /* Vertices are just an array of floats making up each attribute in
00155     * turn.  Currently fixed at 4 floats, but should change in time.
00156     * Codegen will help cope with this.
00157     */
00158    const float (*vmax)[4];
00159    const float (*vmid)[4];
00160    const float (*vmin)[4];
00161    const float (*vprovoke)[4];
00162 
00163    struct edge ebot;
00164    struct edge etop;
00165    struct edge emaj;
00166 
00167    float oneoverarea;
00168 
00169    struct tgsi_interp_coef coef[PIPE_MAX_SHADER_INPUTS];
00170    struct tgsi_interp_coef posCoef;  /* For Z, W */
00171    struct quad_header quad;
00172 
00173 #if SP_NUM_QUAD_THREADS > 1
00174    struct quad_job_que que;
00175    struct thread_info threads[SP_NUM_QUAD_THREADS];
00176 #endif
00177 
00178    struct {
00179       int left[2];   
00180       int right[2];
00181       int y;
00182       unsigned y_flags;
00183       unsigned mask;     
00184    } span;
00185 
00186 #if DEBUG_FRAGS
00187    uint numFragsEmitted;  
00188    uint numFragsWritten;  
00189 #endif
00190 
00191    unsigned winding;            /* which winding to cull */
00192 };
00193 
00194 #if SP_NUM_QUAD_THREADS > 1
00195 
00196 static PIPE_THREAD_ROUTINE( quad_thread, param )
00197 {
00198    struct thread_info *info = (struct thread_info *) param;
00199    struct quad_job_que *que = &info->setup->que;
00200 
00201    for (;;) {
00202       struct quad_job job;
00203       boolean full;
00204 
00205       /* Wait for an available job.
00206        */
00207       pipe_mutex_lock( que->que_mutex );
00208       while (que->last == que->first)
00209          pipe_condvar_wait( que->que_notempty_condvar, que->que_mutex );
00210 
00211       /* See if the que is full.
00212        */
00213       full = (que->last + 1) % NUM_QUAD_JOBS == que->first;
00214 
00215       /* Take a job and remove it from que.
00216        */
00217       job = que->jobs[que->first];
00218       que->first = (que->first + 1) % NUM_QUAD_JOBS;
00219 
00220       /* Notify the producer if the que is not full.
00221        */
00222       if (full)
00223          pipe_condvar_signal( que->que_notfull_condvar );
00224       pipe_mutex_unlock( que->que_mutex );
00225 
00226       job.routine( info->setup, info->id, &job );
00227 
00228       /* Notify the producer if that's the last finished job.
00229        */
00230       pipe_mutex_lock( que->que_mutex );
00231       que->jobs_done++;
00232       if (que->jobs_added == que->jobs_done)
00233          pipe_condvar_signal( que->que_done_condvar );
00234       pipe_mutex_unlock( que->que_mutex );
00235    }
00236 
00237    return NULL;
00238 }
00239 
00240 #define WAIT_FOR_COMPLETION(setup) \
00241    do {\
00242       pipe_mutex_lock( setup->que.que_mutex );\
00243       if (!INSTANT_NOTEMPTY_NOTIFY)\
00244          pipe_condvar_broadcast( setup->que.que_notempty_condvar );\
00245       while (setup->que.jobs_added != setup->que.jobs_done)\
00246          pipe_condvar_wait( setup->que.que_done_condvar, setup->que.que_mutex );\
00247       pipe_mutex_unlock( setup->que.que_mutex );\
00248    } while (0)
00249 
00250 #else
00251 
00252 #define WAIT_FOR_COMPLETION(setup) ((void) 0)
00253 
00254 #endif
00255 
00259 static INLINE boolean
00260 is_inf_or_nan(float x)
00261 {
00262    union fi tmp;
00263    tmp.f = x;
00264    return !(int)((unsigned int)((tmp.i & 0x7fffffff)-0x7f800000) >> 31);
00265 }
00266 
00267 
00268 static boolean cull_tri( struct setup_context *setup,
00269                       float det )
00270 {
00271    if (det != 0) 
00272    {   
00273       /* if (det < 0 then Z points toward camera and triangle is 
00274        * counter-clockwise winding.
00275        */
00276       unsigned winding = (det < 0) ? PIPE_WINDING_CCW : PIPE_WINDING_CW;
00277       
00278       if ((winding & setup->winding) == 0) 
00279          return FALSE;
00280    }
00281 
00282    /* Culled:
00283     */
00284    return TRUE;
00285 }
00286 
00287 
00288 
00292 static INLINE void
00293 quad_clip( struct setup_context *setup, struct quad_header *quad )
00294 {
00295    const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect;
00296    const int minx = (int) cliprect->minx;
00297    const int maxx = (int) cliprect->maxx;
00298    const int miny = (int) cliprect->miny;
00299    const int maxy = (int) cliprect->maxy;
00300 
00301    if (quad->input.x0 >= maxx ||
00302        quad->input.y0 >= maxy ||
00303        quad->input.x0 + 1 < minx ||
00304        quad->input.y0 + 1 < miny) {
00305       /* totally clipped */
00306       quad->inout.mask = 0x0;
00307       return;
00308    }
00309    if (quad->input.x0 < minx)
00310       quad->inout.mask &= (MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT);
00311    if (quad->input.y0 < miny)
00312       quad->inout.mask &= (MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT);
00313    if (quad->input.x0 == maxx - 1)
00314       quad->inout.mask &= (MASK_BOTTOM_LEFT | MASK_TOP_LEFT);
00315    if (quad->input.y0 == maxy - 1)
00316       quad->inout.mask &= (MASK_TOP_LEFT | MASK_TOP_RIGHT);
00317 }
00318 
00319 
00323 static INLINE void
00324 clip_emit_quad( struct setup_context *setup, struct quad_header *quad, uint thread )
00325 {
00326    quad_clip( setup, quad );
00327    if (quad->inout.mask) {
00328       struct softpipe_context *sp = setup->softpipe;
00329 
00330       sp->quad[thread].first->run( sp->quad[thread].first, quad );
00331    }
00332 }
00333 
00334 #if SP_NUM_QUAD_THREADS > 1
00335 
00336 static void
00337 clip_emit_quad_job( struct setup_context *setup, uint thread, struct quad_job *job )
00338 {
00339    struct quad_header quad;
00340 
00341    quad.input = job->input;
00342    quad.inout = job->inout;
00343    quad.coef = setup->quad.coef;
00344    quad.posCoef = setup->quad.posCoef;
00345    quad.nr_attrs = setup->quad.nr_attrs;
00346    clip_emit_quad( setup, &quad, thread );
00347 }
00348 
00349 #define CLIP_EMIT_QUAD(setup) add_quad_job( &setup->que, &setup->quad, clip_emit_quad_job )
00350 
00351 #else
00352 
00353 #define CLIP_EMIT_QUAD(setup) clip_emit_quad( setup, &setup->quad, 0 )
00354 
00355 #endif
00356 
00360 static INLINE void
00361 emit_quad( struct setup_context *setup, struct quad_header *quad, uint thread )
00362 {
00363    struct softpipe_context *sp = setup->softpipe;
00364 #if DEBUG_FRAGS
00365    uint mask = quad->inout.mask;
00366 #endif
00367 
00368 #if DEBUG_FRAGS
00369    if (mask & 1) setup->numFragsEmitted++;
00370    if (mask & 2) setup->numFragsEmitted++;
00371    if (mask & 4) setup->numFragsEmitted++;
00372    if (mask & 8) setup->numFragsEmitted++;
00373 #endif
00374    sp->quad[thread].first->run( sp->quad[thread].first, quad );
00375 #if DEBUG_FRAGS
00376    mask = quad->inout.mask;
00377    if (mask & 1) setup->numFragsWritten++;
00378    if (mask & 2) setup->numFragsWritten++;
00379    if (mask & 4) setup->numFragsWritten++;
00380    if (mask & 8) setup->numFragsWritten++;
00381 #endif
00382 }
00383 
00384 #if SP_NUM_QUAD_THREADS > 1
00385 
00386 static void
00387 emit_quad_job( struct setup_context *setup, uint thread, struct quad_job *job )
00388 {
00389    struct quad_header quad;
00390 
00391    quad.input = job->input;
00392    quad.inout = job->inout;
00393    quad.coef = setup->quad.coef;
00394    quad.posCoef = setup->quad.posCoef;
00395    quad.nr_attrs = setup->quad.nr_attrs;
00396    emit_quad( setup, &quad, thread );
00397 }
00398 
00399 #define EMIT_QUAD(setup,x,y,mask) do {\
00400       setup->quad.input.x0 = x;\
00401       setup->quad.input.y0 = y;\
00402       setup->quad.inout.mask = mask;\
00403       add_quad_job( &setup->que, &setup->quad, emit_quad_job );\
00404    } while (0)
00405 
00406 #else
00407 
00408 #define EMIT_QUAD(setup,x,y,mask) do {\
00409       setup->quad.input.x0 = x;\
00410       setup->quad.input.y0 = y;\
00411       setup->quad.inout.mask = mask;\
00412       emit_quad( setup, &setup->quad, 0 );\
00413    } while (0)
00414 
00415 #endif
00416 
00421 static INLINE int block( int x )
00422 {
00423    return x & ~1;
00424 }
00425 
00426 
00430 static void flush_spans( struct setup_context *setup )
00431 {
00432    const int xleft0 = setup->span.left[0];
00433    const int xleft1 = setup->span.left[1];
00434    const int xright0 = setup->span.right[0];
00435    const int xright1 = setup->span.right[1];
00436    int minleft, maxright;
00437    int x;
00438 
00439    switch (setup->span.y_flags) {
00440    case 0x3:
00441       /* both odd and even lines written (both quad rows) */
00442       minleft = block(MIN2(xleft0, xleft1));
00443       maxright = block(MAX2(xright0, xright1));
00444       for (x = minleft; x <= maxright; x += 2) {
00445          /* determine which of the four pixels is inside the span bounds */
00446          uint mask = 0x0;
00447          if (x >= xleft0 && x < xright0)
00448             mask |= MASK_TOP_LEFT;
00449          if (x >= xleft1 && x < xright1)
00450             mask |= MASK_BOTTOM_LEFT;
00451          if (x+1 >= xleft0 && x+1 < xright0)
00452             mask |= MASK_TOP_RIGHT;
00453          if (x+1 >= xleft1 && x+1 < xright1)
00454             mask |= MASK_BOTTOM_RIGHT;
00455          EMIT_QUAD( setup, x, setup->span.y, mask );
00456       }
00457       break;
00458 
00459    case 0x1:
00460       /* only even line written (quad top row) */
00461       minleft = block(xleft0);
00462       maxright = block(xright0);
00463       for (x = minleft; x <= maxright; x += 2) {
00464          uint mask = 0x0;
00465          if (x >= xleft0 && x < xright0)
00466             mask |= MASK_TOP_LEFT;
00467          if (x+1 >= xleft0 && x+1 < xright0)
00468             mask |= MASK_TOP_RIGHT;
00469          EMIT_QUAD( setup, x, setup->span.y, mask );
00470       }
00471       break;
00472 
00473    case 0x2:
00474       /* only odd line written (quad bottom row) */
00475       minleft = block(xleft1);
00476       maxright = block(xright1);
00477       for (x = minleft; x <= maxright; x += 2) {
00478          uint mask = 0x0;
00479          if (x >= xleft1 && x < xright1)
00480             mask |= MASK_BOTTOM_LEFT;
00481          if (x+1 >= xleft1 && x+1 < xright1)
00482             mask |= MASK_BOTTOM_RIGHT;
00483          EMIT_QUAD( setup, x, setup->span.y, mask );
00484       }
00485       break;
00486 
00487    default:
00488       return;
00489    }
00490 
00491    setup->span.y = 0;
00492    setup->span.y_flags = 0;
00493    setup->span.right[0] = 0;
00494    setup->span.right[1] = 0;
00495 }
00496 
00497 
00498 #if DEBUG_VERTS
00499 static void print_vertex(const struct setup_context *setup,
00500                          const float (*v)[4])
00501 {
00502    int i;
00503    debug_printf("   Vertex: (%p)\n", v);
00504    for (i = 0; i < setup->quad.nr_attrs; i++) {
00505       debug_printf("     %d: %f %f %f %f\n",  i,
00506               v[i][0], v[i][1], v[i][2], v[i][3]);
00507    }
00508 }
00509 #endif
00510 
00514 static boolean setup_sort_vertices( struct setup_context *setup,
00515                                     float det,
00516                                     const float (*v0)[4],
00517                                     const float (*v1)[4],
00518                                     const float (*v2)[4] )
00519 {
00520    setup->vprovoke = v2;
00521 
00522    /* determine bottom to top order of vertices */
00523    {
00524       float y0 = v0[0][1];
00525       float y1 = v1[0][1];
00526       float y2 = v2[0][1];
00527       if (y0 <= y1) {
00528          if (y1 <= y2) {
00529             /* y0<=y1<=y2 */
00530             setup->vmin = v0;
00531             setup->vmid = v1;
00532             setup->vmax = v2;
00533          }
00534          else if (y2 <= y0) {
00535             /* y2<=y0<=y1 */
00536             setup->vmin = v2;
00537             setup->vmid = v0;
00538             setup->vmax = v1;
00539          }
00540          else {
00541             /* y0<=y2<=y1 */
00542             setup->vmin = v0;
00543             setup->vmid = v2;
00544             setup->vmax = v1;
00545          }
00546       }
00547       else {
00548          if (y0 <= y2) {
00549             /* y1<=y0<=y2 */
00550             setup->vmin = v1;
00551             setup->vmid = v0;
00552             setup->vmax = v2;
00553          }
00554          else if (y2 <= y1) {
00555             /* y2<=y1<=y0 */
00556             setup->vmin = v2;
00557             setup->vmid = v1;
00558             setup->vmax = v0;
00559          }
00560          else {
00561             /* y1<=y2<=y0 */
00562             setup->vmin = v1;
00563             setup->vmid = v2;
00564             setup->vmax = v0;
00565          }
00566       }
00567    }
00568 
00569    setup->ebot.dx = setup->vmid[0][0] - setup->vmin[0][0];
00570    setup->ebot.dy = setup->vmid[0][1] - setup->vmin[0][1];
00571    setup->emaj.dx = setup->vmax[0][0] - setup->vmin[0][0];
00572    setup->emaj.dy = setup->vmax[0][1] - setup->vmin[0][1];
00573    setup->etop.dx = setup->vmax[0][0] - setup->vmid[0][0];
00574    setup->etop.dy = setup->vmax[0][1] - setup->vmid[0][1];
00575 
00576    /*
00577     * Compute triangle's area.  Use 1/area to compute partial
00578     * derivatives of attributes later.
00579     *
00580     * The area will be the same as prim->det, but the sign may be
00581     * different depending on how the vertices get sorted above.
00582     *
00583     * To determine whether the primitive is front or back facing we
00584     * use the prim->det value because its sign is correct.
00585     */
00586    {
00587       const float area = (setup->emaj.dx * setup->ebot.dy -
00588                             setup->ebot.dx * setup->emaj.dy);
00589 
00590       setup->oneoverarea = 1.0f / area;
00591 
00592       /*
00593       debug_printf("%s one-over-area %f  area %f  det %f\n",
00594                    __FUNCTION__, setup->oneoverarea, area, det );
00595       */
00596       if (is_inf_or_nan(setup->oneoverarea))
00597          return FALSE;
00598    }
00599 
00600    /* We need to know if this is a front or back-facing triangle for:
00601     *  - the GLSL gl_FrontFacing fragment attribute (bool)
00602     *  - two-sided stencil test
00603     */
00604    setup->quad.input.facing = (det > 0.0) ^ (setup->softpipe->rasterizer->front_winding == PIPE_WINDING_CW);
00605 
00606    return TRUE;
00607 }
00608 
00609 
00617 static void const_coeff( struct setup_context *setup,
00618                          struct tgsi_interp_coef *coef,
00619                          uint vertSlot, uint i)
00620 {
00621    assert(i <= 3);
00622 
00623    coef->dadx[i] = 0;
00624    coef->dady[i] = 0;
00625 
00626    /* need provoking vertex info!
00627     */
00628    coef->a0[i] = setup->vprovoke[vertSlot][i];
00629 }
00630 
00631 
00636 static void tri_linear_coeff( struct setup_context *setup,
00637                               struct tgsi_interp_coef *coef,
00638                               uint vertSlot, uint i)
00639 {
00640    float botda = setup->vmid[vertSlot][i] - setup->vmin[vertSlot][i];
00641    float majda = setup->vmax[vertSlot][i] - setup->vmin[vertSlot][i];
00642    float a = setup->ebot.dy * majda - botda * setup->emaj.dy;
00643    float b = setup->emaj.dx * botda - majda * setup->ebot.dx;
00644    float dadx = a * setup->oneoverarea;
00645    float dady = b * setup->oneoverarea;
00646 
00647    assert(i <= 3);
00648 
00649    coef->dadx[i] = dadx;
00650    coef->dady[i] = dady;
00651 
00652    /* calculate a0 as the value which would be sampled for the
00653     * fragment at (0,0), taking into account that we want to sample at
00654     * pixel centers, in other words (0.5, 0.5).
00655     *
00656     * this is neat but unfortunately not a good way to do things for
00657     * triangles with very large values of dadx or dady as it will
00658     * result in the subtraction and re-addition from a0 of a very
00659     * large number, which means we'll end up loosing a lot of the
00660     * fractional bits and precision from a0.  the way to fix this is
00661     * to define a0 as the sample at a pixel center somewhere near vmin
00662     * instead - i'll switch to this later.
00663     */
00664    coef->a0[i] = (setup->vmin[vertSlot][i] -
00665                   (dadx * (setup->vmin[0][0] - 0.5f) +
00666                    dady * (setup->vmin[0][1] - 0.5f)));
00667 
00668    /*
00669    debug_printf("attr[%d].%c: %f dx:%f dy:%f\n",
00670                 slot, "xyzw"[i],
00671                 setup->coef[slot].a0[i],
00672                 setup->coef[slot].dadx[i],
00673                 setup->coef[slot].dady[i]);
00674    */
00675 }
00676 
00677 
00686 static void tri_persp_coeff( struct setup_context *setup,
00687                              struct tgsi_interp_coef *coef,
00688                              uint vertSlot, uint i)
00689 {
00690    /* premultiply by 1/w  (v[0][3] is always W):
00691     */
00692    float mina = setup->vmin[vertSlot][i] * setup->vmin[0][3];
00693    float mida = setup->vmid[vertSlot][i] * setup->vmid[0][3];
00694    float maxa = setup->vmax[vertSlot][i] * setup->vmax[0][3];
00695    float botda = mida - mina;
00696    float majda = maxa - mina;
00697    float a = setup->ebot.dy * majda - botda * setup->emaj.dy;
00698    float b = setup->emaj.dx * botda - majda * setup->ebot.dx;
00699    float dadx = a * setup->oneoverarea;
00700    float dady = b * setup->oneoverarea;
00701 
00702    /*
00703    debug_printf("tri persp %d,%d: %f %f %f\n", vertSlot, i,
00704                 setup->vmin[vertSlot][i],
00705                 setup->vmid[vertSlot][i],
00706                 setup->vmax[vertSlot][i]
00707           );
00708    */
00709    assert(i <= 3);
00710 
00711    coef->dadx[i] = dadx;
00712    coef->dady[i] = dady;
00713    coef->a0[i] = (mina -
00714                   (dadx * (setup->vmin[0][0] - 0.5f) +
00715                    dady * (setup->vmin[0][1] - 0.5f)));
00716 }
00717 
00718 
00725 static void
00726 setup_fragcoord_coeff(struct setup_context *setup, uint slot)
00727 {
00728    /*X*/
00729    setup->coef[slot].a0[0] = 0;
00730    setup->coef[slot].dadx[0] = 1.0;
00731    setup->coef[slot].dady[0] = 0.0;
00732    /*Y*/
00733    if (setup->softpipe->rasterizer->origin_lower_left) {
00734       /* y=0=bottom */
00735       const int winHeight = setup->softpipe->framebuffer.height;
00736       setup->coef[slot].a0[1] = (float) (winHeight - 1);
00737       setup->coef[slot].dady[1] = -1.0;
00738    }
00739    else {
00740       /* y=0=top */
00741       setup->coef[slot].a0[1] = 0.0;
00742       setup->coef[slot].dady[1] = 1.0;
00743    }
00744    setup->coef[slot].dadx[1] = 0.0;
00745    /*Z*/
00746    setup->coef[slot].a0[2] = setup->posCoef.a0[2];
00747    setup->coef[slot].dadx[2] = setup->posCoef.dadx[2];
00748    setup->coef[slot].dady[2] = setup->posCoef.dady[2];
00749    /*W*/
00750    setup->coef[slot].a0[3] = setup->posCoef.a0[3];
00751    setup->coef[slot].dadx[3] = setup->posCoef.dadx[3];
00752    setup->coef[slot].dady[3] = setup->posCoef.dady[3];
00753 }
00754 
00755 
00756 
00761 static void setup_tri_coefficients( struct setup_context *setup )
00762 {
00763    struct softpipe_context *softpipe = setup->softpipe;
00764    const struct sp_fragment_shader *spfs = softpipe->fs;
00765    const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe);
00766    uint fragSlot;
00767 
00768    /* z and w are done by linear interpolation:
00769     */
00770    tri_linear_coeff(setup, &setup->posCoef, 0, 2);
00771    tri_linear_coeff(setup, &setup->posCoef, 0, 3);
00772 
00773    /* setup interpolation for all the remaining attributes:
00774     */
00775    for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) {
00776       const uint vertSlot = vinfo->attrib[fragSlot].src_index;
00777       uint j;
00778 
00779       switch (vinfo->attrib[fragSlot].interp_mode) {
00780       case INTERP_CONSTANT:
00781          for (j = 0; j < NUM_CHANNELS; j++)
00782             const_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
00783          break;
00784       case INTERP_LINEAR:
00785          for (j = 0; j < NUM_CHANNELS; j++)
00786             tri_linear_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
00787          break;
00788       case INTERP_PERSPECTIVE:
00789          for (j = 0; j < NUM_CHANNELS; j++)
00790             tri_persp_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
00791          break;
00792       case INTERP_POS:
00793          setup_fragcoord_coeff(setup, fragSlot);
00794          break;
00795       default:
00796          assert(0);
00797       }
00798 
00799       if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FOG) {
00800          /* FOG.y = front/back facing  XXX fix this */
00801          setup->coef[fragSlot].a0[1] = 1.0f - setup->quad.input.facing;
00802          setup->coef[fragSlot].dadx[1] = 0.0;
00803          setup->coef[fragSlot].dady[1] = 0.0;
00804       }
00805    }
00806 }
00807 
00808 
00809 
00810 static void setup_tri_edges( struct setup_context *setup )
00811 {
00812    float vmin_x = setup->vmin[0][0] + 0.5f;
00813    float vmid_x = setup->vmid[0][0] + 0.5f;
00814 
00815    float vmin_y = setup->vmin[0][1] - 0.5f;
00816    float vmid_y = setup->vmid[0][1] - 0.5f;
00817    float vmax_y = setup->vmax[0][1] - 0.5f;
00818 
00819    setup->emaj.sy = ceilf(vmin_y);
00820    setup->emaj.lines = (int) ceilf(vmax_y - setup->emaj.sy);
00821    setup->emaj.dxdy = setup->emaj.dx / setup->emaj.dy;
00822    setup->emaj.sx = vmin_x + (setup->emaj.sy - vmin_y) * setup->emaj.dxdy;
00823 
00824    setup->etop.sy = ceilf(vmid_y);
00825    setup->etop.lines = (int) ceilf(vmax_y - setup->etop.sy);
00826    setup->etop.dxdy = setup->etop.dx / setup->etop.dy;
00827    setup->etop.sx = vmid_x + (setup->etop.sy - vmid_y) * setup->etop.dxdy;
00828 
00829    setup->ebot.sy = ceilf(vmin_y);
00830    setup->ebot.lines = (int) ceilf(vmid_y - setup->ebot.sy);
00831    setup->ebot.dxdy = setup->ebot.dx / setup->ebot.dy;
00832    setup->ebot.sx = vmin_x + (setup->ebot.sy - vmin_y) * setup->ebot.dxdy;
00833 }
00834 
00835 
00840 static void subtriangle( struct setup_context *setup,
00841                          struct edge *eleft,
00842                          struct edge *eright,
00843                          unsigned lines )
00844 {
00845    const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect;
00846    const int minx = (int) cliprect->minx;
00847    const int maxx = (int) cliprect->maxx;
00848    const int miny = (int) cliprect->miny;
00849    const int maxy = (int) cliprect->maxy;
00850    int y, start_y, finish_y;
00851    int sy = (int)eleft->sy;
00852 
00853    assert((int)eleft->sy == (int) eright->sy);
00854 
00855    /* clip top/bottom */
00856    start_y = sy;
00857    finish_y = sy + lines;
00858 
00859    if (start_y < miny)
00860       start_y = miny;
00861 
00862    if (finish_y > maxy)
00863       finish_y = maxy;
00864 
00865    start_y -= sy;
00866    finish_y -= sy;
00867 
00868    /*
00869    debug_printf("%s %d %d\n", __FUNCTION__, start_y, finish_y);
00870    */
00871 
00872    for (y = start_y; y < finish_y; y++) {
00873 
00874       /* avoid accumulating adds as floats don't have the precision to
00875        * accurately iterate large triangle edges that way.  luckily we
00876        * can just multiply these days.
00877        *
00878        * this is all drowned out by the attribute interpolation anyway.
00879        */
00880       int left = (int)(eleft->sx + y * eleft->dxdy);
00881       int right = (int)(eright->sx + y * eright->dxdy);
00882 
00883       /* clip left/right */
00884       if (left < minx)
00885          left = minx;
00886       if (right > maxx)
00887          right = maxx;
00888 
00889       if (left < right) {
00890          int _y = sy + y;
00891          if (block(_y) != setup->span.y) {
00892             flush_spans(setup);
00893             setup->span.y = block(_y);
00894          }
00895 
00896          setup->span.left[_y&1] = left;
00897          setup->span.right[_y&1] = right;
00898          setup->span.y_flags |= 1<<(_y&1);
00899       }
00900    }
00901 
00902 
00903    /* save the values so that emaj can be restarted:
00904     */
00905    eleft->sx += lines * eleft->dxdy;
00906    eright->sx += lines * eright->dxdy;
00907    eleft->sy += lines;
00908    eright->sy += lines;
00909 }
00910 
00911 
00917 static float
00918 calc_det( const float (*v0)[4],
00919           const float (*v1)[4],
00920           const float (*v2)[4] )
00921 {
00922    /* edge vectors e = v0 - v2, f = v1 - v2 */
00923    const float ex = v0[0][0] - v2[0][0];
00924    const float ey = v0[0][1] - v2[0][1];
00925    const float fx = v1[0][0] - v2[0][0];
00926    const float fy = v1[0][1] - v2[0][1];
00927 
00928    /* det = cross(e,f).z */
00929    return ex * fy - ey * fx;
00930 }
00931 
00932 
00936 void setup_tri( struct setup_context *setup,
00937                 const float (*v0)[4],
00938                 const float (*v1)[4],
00939                 const float (*v2)[4] )
00940 {
00941    float det;
00942 
00943 #if DEBUG_VERTS
00944    debug_printf("Setup triangle:\n");
00945    print_vertex(setup, v0);
00946    print_vertex(setup, v1);
00947    print_vertex(setup, v2);
00948 #endif
00949 
00950    if (setup->softpipe->no_rast)
00951       return;
00952    
00953    det = calc_det(v0, v1, v2);
00954    /*
00955    debug_printf("%s\n", __FUNCTION__ );
00956    */
00957 
00958 #if DEBUG_FRAGS
00959    setup->numFragsEmitted = 0;
00960    setup->numFragsWritten = 0;
00961 #endif
00962 
00963    if (cull_tri( setup, det ))
00964       return;
00965 
00966    if (!setup_sort_vertices( setup, det, v0, v1, v2 ))
00967       return;
00968    setup_tri_coefficients( setup );
00969    setup_tri_edges( setup );
00970 
00971    setup->quad.input.prim = PRIM_TRI;
00972 
00973    setup->span.y = 0;
00974    setup->span.y_flags = 0;
00975    setup->span.right[0] = 0;
00976    setup->span.right[1] = 0;
00977    /*   setup->span.z_mode = tri_z_mode( setup->ctx ); */
00978 
00979    /*   init_constant_attribs( setup ); */
00980 
00981    if (setup->oneoverarea < 0.0) {
00982       /* emaj on left:
00983        */
00984       subtriangle( setup, &setup->emaj, &setup->ebot, setup->ebot.lines );
00985       subtriangle( setup, &setup->emaj, &setup->etop, setup->etop.lines );
00986    }
00987    else {
00988       /* emaj on right:
00989        */
00990       subtriangle( setup, &setup->ebot, &setup->emaj, setup->ebot.lines );
00991       subtriangle( setup, &setup->etop, &setup->emaj, setup->etop.lines );
00992    }
00993 
00994    flush_spans( setup );
00995 
00996    WAIT_FOR_COMPLETION(setup);
00997 
00998 #if DEBUG_FRAGS
00999    printf("Tri: %u frags emitted, %u written\n",
01000           setup->numFragsEmitted,
01001           setup->numFragsWritten);
01002 #endif
01003 }
01004 
01005 
01006 
01011 static void
01012 line_linear_coeff(struct setup_context *setup,
01013                   struct tgsi_interp_coef *coef,
01014                   uint vertSlot, uint i)
01015 {
01016    const float da = setup->vmax[vertSlot][i] - setup->vmin[vertSlot][i];
01017    const float dadx = da * setup->emaj.dx * setup->oneoverarea;
01018    const float dady = da * setup->emaj.dy * setup->oneoverarea;
01019    coef->dadx[i] = dadx;
01020    coef->dady[i] = dady;
01021    coef->a0[i] = (setup->vmin[vertSlot][i] -
01022                   (dadx * (setup->vmin[0][0] - 0.5f) +
01023                    dady * (setup->vmin[0][1] - 0.5f)));
01024 }
01025 
01026 
01031 static void
01032 line_persp_coeff(struct setup_context *setup,
01033                   struct tgsi_interp_coef *coef,
01034                   uint vertSlot, uint i)
01035 {
01036    /* XXX double-check/verify this arithmetic */
01037    const float a0 = setup->vmin[vertSlot][i] * setup->vmin[0][3];
01038    const float a1 = setup->vmax[vertSlot][i] * setup->vmax[0][3];
01039    const float da = a1 - a0;
01040    const float dadx = da * setup->emaj.dx * setup->oneoverarea;
01041    const float dady = da * setup->emaj.dy * setup->oneoverarea;
01042    coef->dadx[i] = dadx;
01043    coef->dady[i] = dady;
01044    coef->a0[i] = (setup->vmin[vertSlot][i] -
01045                   (dadx * (setup->vmin[0][0] - 0.5f) +
01046                    dady * (setup->vmin[0][1] - 0.5f)));
01047 }
01048 
01049 
01054 static INLINE boolean
01055 setup_line_coefficients(struct setup_context *setup,
01056                         const float (*v0)[4],
01057                         const float (*v1)[4])
01058 {
01059    struct softpipe_context *softpipe = setup->softpipe;
01060    const struct sp_fragment_shader *spfs = softpipe->fs;
01061    const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe);
01062    uint fragSlot;
01063    float area;
01064 
01065    /* use setup->vmin, vmax to point to vertices */
01066    setup->vprovoke = v1;
01067    setup->vmin = v0;
01068    setup->vmax = v1;
01069 
01070    setup->emaj.dx = setup->vmax[0][0] - setup->vmin[0][0];
01071    setup->emaj.dy = setup->vmax[0][1] - setup->vmin[0][1];
01072 
01073    /* NOTE: this is not really area but something proportional to it */
01074    area = setup->emaj.dx * setup->emaj.dx + setup->emaj.dy * setup->emaj.dy;
01075    if (area == 0.0f || is_inf_or_nan(area))
01076       return FALSE;
01077    setup->oneoverarea = 1.0f / area;
01078 
01079    /* z and w are done by linear interpolation:
01080     */
01081    line_linear_coeff(setup, &setup->posCoef, 0, 2);
01082    line_linear_coeff(setup, &setup->posCoef, 0, 3);
01083 
01084    /* setup interpolation for all the remaining attributes:
01085     */
01086    for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) {
01087       const uint vertSlot = vinfo->attrib[fragSlot].src_index;
01088       uint j;
01089 
01090       switch (vinfo->attrib[fragSlot].interp_mode) {
01091       case INTERP_CONSTANT:
01092          for (j = 0; j < NUM_CHANNELS; j++)
01093             const_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
01094          break;
01095       case INTERP_LINEAR:
01096          for (j = 0; j < NUM_CHANNELS; j++)
01097             line_linear_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
01098          break;
01099       case INTERP_PERSPECTIVE:
01100          for (j = 0; j < NUM_CHANNELS; j++)
01101             line_persp_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
01102          break;
01103       case INTERP_POS:
01104          setup_fragcoord_coeff(setup, fragSlot);
01105          break;
01106       default:
01107          assert(0);
01108       }
01109 
01110       if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FOG) {
01111          /* FOG.y = front/back facing  XXX fix this */
01112          setup->coef[fragSlot].a0[1] = 1.0f - setup->quad.input.facing;
01113          setup->coef[fragSlot].dadx[1] = 0.0;
01114          setup->coef[fragSlot].dady[1] = 0.0;
01115       }
01116    }
01117    return TRUE;
01118 }
01119 
01120 
01124 static INLINE void
01125 plot(struct setup_context *setup, int x, int y)
01126 {
01127    const int iy = y & 1;
01128    const int ix = x & 1;
01129    const int quadX = x - ix;
01130    const int quadY = y - iy;
01131    const int mask = (1 << ix) << (2 * iy);
01132 
01133    if (quadX != setup->quad.input.x0 ||
01134        quadY != setup->quad.input.y0)
01135    {
01136       /* flush prev quad, start new quad */
01137 
01138       if (setup->quad.input.x0 != -1)
01139          CLIP_EMIT_QUAD(setup);
01140 
01141       setup->quad.input.x0 = quadX;
01142       setup->quad.input.y0 = quadY;
01143       setup->quad.inout.mask = 0x0;
01144    }
01145 
01146    setup->quad.inout.mask |= mask;
01147 }
01148 
01149 
01155 void
01156 setup_line(struct setup_context *setup,
01157            const float (*v0)[4],
01158            const float (*v1)[4])
01159 {
01160    int x0 = (int) v0[0][0];
01161    int x1 = (int) v1[0][0];
01162    int y0 = (int) v0[0][1];
01163    int y1 = (int) v1[0][1];
01164    int dx = x1 - x0;
01165    int dy = y1 - y0;
01166    int xstep, ystep;
01167 
01168 #if DEBUG_VERTS
01169    debug_printf("Setup line:\n");
01170    print_vertex(setup, v0);
01171    print_vertex(setup, v1);
01172 #endif
01173 
01174    if (setup->softpipe->no_rast)
01175       return;
01176 
01177    if (dx == 0 && dy == 0)
01178       return;
01179 
01180    if (!setup_line_coefficients(setup, v0, v1))
01181       return;
01182 
01183    assert(v0[0][0] < 1.0e9);
01184    assert(v0[0][1] < 1.0e9);
01185    assert(v1[0][0] < 1.0e9);
01186    assert(v1[0][1] < 1.0e9);
01187 
01188    if (dx < 0) {
01189       dx = -dx;   /* make positive */
01190       xstep = -1;
01191    }
01192    else {
01193       xstep = 1;
01194    }
01195 
01196    if (dy < 0) {
01197       dy = -dy;   /* make positive */
01198       ystep = -1;
01199    }
01200    else {
01201       ystep = 1;
01202    }
01203 
01204    assert(dx >= 0);
01205    assert(dy >= 0);
01206 
01207    setup->quad.input.x0 = setup->quad.input.y0 = -1;
01208    setup->quad.inout.mask = 0x0;
01209    setup->quad.input.prim = PRIM_LINE;
01210    /* XXX temporary: set coverage to 1.0 so the line appears
01211     * if AA mode happens to be enabled.
01212     */
01213    setup->quad.input.coverage[0] =
01214    setup->quad.input.coverage[1] =
01215    setup->quad.input.coverage[2] =
01216    setup->quad.input.coverage[3] = 1.0;
01217 
01218    if (dx > dy) {
01219       /*** X-major line ***/
01220       int i;
01221       const int errorInc = dy + dy;
01222       int error = errorInc - dx;
01223       const int errorDec = error - dx;
01224 
01225       for (i = 0; i < dx; i++) {
01226          plot(setup, x0, y0);
01227 
01228          x0 += xstep;
01229          if (error < 0) {
01230             error += errorInc;
01231          }
01232          else {
01233             error += errorDec;
01234             y0 += ystep;
01235          }
01236       }
01237    }
01238    else {
01239       /*** Y-major line ***/
01240       int i;
01241       const int errorInc = dx + dx;
01242       int error = errorInc - dy;
01243       const int errorDec = error - dy;
01244 
01245       for (i = 0; i < dy; i++) {
01246          plot(setup, x0, y0);
01247 
01248          y0 += ystep;
01249          if (error < 0) {
01250             error += errorInc;
01251          }
01252          else {
01253             error += errorDec;
01254             x0 += xstep;
01255          }
01256       }
01257    }
01258 
01259    /* draw final quad */
01260    if (setup->quad.inout.mask) {
01261       CLIP_EMIT_QUAD(setup);
01262    }
01263 
01264    WAIT_FOR_COMPLETION(setup);
01265 }
01266 
01267 
01268 static void
01269 point_persp_coeff(struct setup_context *setup,
01270                   const float (*vert)[4],
01271                   struct tgsi_interp_coef *coef,
01272                   uint vertSlot, uint i)
01273 {
01274    assert(i <= 3);
01275    coef->dadx[i] = 0.0F;
01276    coef->dady[i] = 0.0F;
01277    coef->a0[i] = vert[vertSlot][i] * vert[0][3];
01278 }
01279 
01280 
01286 void
01287 setup_point( struct setup_context *setup,
01288              const float (*v0)[4] )
01289 {
01290    struct softpipe_context *softpipe = setup->softpipe;
01291    const struct sp_fragment_shader *spfs = softpipe->fs;
01292    const int sizeAttr = setup->softpipe->psize_slot;
01293    const float size
01294       = sizeAttr > 0 ? v0[sizeAttr][0]
01295       : setup->softpipe->rasterizer->point_size;
01296    const float halfSize = 0.5F * size;
01297    const boolean round = (boolean) setup->softpipe->rasterizer->point_smooth;
01298    const float x = v0[0][0];  /* Note: data[0] is always position */
01299    const float y = v0[0][1];
01300    const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe);
01301    uint fragSlot;
01302 
01303 #if DEBUG_VERTS
01304    debug_printf("Setup point:\n");
01305    print_vertex(setup, v0);
01306 #endif
01307 
01308    if (softpipe->no_rast)
01309       return;
01310 
01311    /* For points, all interpolants are constant-valued.
01312     * However, for point sprites, we'll need to setup texcoords appropriately.
01313     * XXX: which coefficients are the texcoords???
01314     * We may do point sprites as textured quads...
01315     *
01316     * KW: We don't know which coefficients are texcoords - ultimately
01317     * the choice of what interpolation mode to use for each attribute
01318     * should be determined by the fragment program, using
01319     * per-attribute declaration statements that include interpolation
01320     * mode as a parameter.  So either the fragment program will have
01321     * to be adjusted for pointsprite vs normal point behaviour, or
01322     * otherwise a special interpolation mode will have to be defined
01323     * which matches the required behaviour for point sprites.  But -
01324     * the latter is not a feature of normal hardware, and as such
01325     * probably should be ruled out on that basis.
01326     */
01327    setup->vprovoke = v0;
01328 
01329    /* setup Z, W */
01330    const_coeff(setup, &setup->posCoef, 0, 2);
01331    const_coeff(setup, &setup->posCoef, 0, 3);
01332 
01333    for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) {
01334       const uint vertSlot = vinfo->attrib[fragSlot].src_index;
01335       uint j;
01336 
01337       switch (vinfo->attrib[fragSlot].interp_mode) {
01338       case INTERP_CONSTANT:
01339          /* fall-through */
01340       case INTERP_LINEAR:
01341          for (j = 0; j < NUM_CHANNELS; j++)
01342             const_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
01343          break;
01344       case INTERP_PERSPECTIVE:
01345          for (j = 0; j < NUM_CHANNELS; j++)
01346             point_persp_coeff(setup, setup->vprovoke,
01347                               &setup->coef[fragSlot], vertSlot, j);
01348          break;
01349       case INTERP_POS:
01350          setup_fragcoord_coeff(setup, fragSlot);
01351          break;
01352       default:
01353          assert(0);
01354       }
01355 
01356       if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FOG) {
01357          /* FOG.y = front/back facing  XXX fix this */
01358          setup->coef[fragSlot].a0[1] = 1.0f - setup->quad.input.facing;
01359          setup->coef[fragSlot].dadx[1] = 0.0;
01360          setup->coef[fragSlot].dady[1] = 0.0;
01361       }
01362    }
01363 
01364    setup->quad.input.prim = PRIM_POINT;
01365 
01366    if (halfSize <= 0.5 && !round) {
01367       /* special case for 1-pixel points */
01368       const int ix = ((int) x) & 1;
01369       const int iy = ((int) y) & 1;
01370       setup->quad.input.x0 = (int) x - ix;
01371       setup->quad.input.y0 = (int) y - iy;
01372       setup->quad.inout.mask = (1 << ix) << (2 * iy);
01373       CLIP_EMIT_QUAD(setup);
01374    }
01375    else {
01376       if (round) {
01377          /* rounded points */
01378          const int ixmin = block((int) (x - halfSize));
01379          const int ixmax = block((int) (x + halfSize));
01380          const int iymin = block((int) (y - halfSize));
01381          const int iymax = block((int) (y + halfSize));
01382          const float rmin = halfSize - 0.7071F;  /* 0.7071 = sqrt(2)/2 */
01383          const float rmax = halfSize + 0.7071F;
01384          const float rmin2 = MAX2(0.0F, rmin * rmin);
01385          const float rmax2 = rmax * rmax;
01386          const float cscale = 1.0F / (rmax2 - rmin2);
01387          int ix, iy;
01388 
01389          for (iy = iymin; iy <= iymax; iy += 2) {
01390             for (ix = ixmin; ix <= ixmax; ix += 2) {
01391                float dx, dy, dist2, cover;
01392 
01393                setup->quad.inout.mask = 0x0;
01394 
01395                dx = (ix + 0.5f) - x;
01396                dy = (iy + 0.5f) - y;
01397                dist2 = dx * dx + dy * dy;
01398                if (dist2 <= rmax2) {
01399                   cover = 1.0F - (dist2 - rmin2) * cscale;
01400                   setup->quad.input.coverage[QUAD_TOP_LEFT] = MIN2(cover, 1.0f);
01401                   setup->quad.inout.mask |= MASK_TOP_LEFT;
01402                }
01403 
01404                dx = (ix + 1.5f) - x;
01405                dy = (iy + 0.5f) - y;
01406                dist2 = dx * dx + dy * dy;
01407                if (dist2 <= rmax2) {
01408                   cover = 1.0F - (dist2 - rmin2) * cscale;
01409                   setup->quad.input.coverage[QUAD_TOP_RIGHT] = MIN2(cover, 1.0f);
01410                   setup->quad.inout.mask |= MASK_TOP_RIGHT;
01411                }
01412 
01413                dx = (ix + 0.5f) - x;
01414                dy = (iy + 1.5f) - y;
01415                dist2 = dx * dx + dy * dy;
01416                if (dist2 <= rmax2) {
01417                   cover = 1.0F - (dist2 - rmin2) * cscale;
01418                   setup->quad.input.coverage[QUAD_BOTTOM_LEFT] = MIN2(cover, 1.0f);
01419                   setup->quad.inout.mask |= MASK_BOTTOM_LEFT;
01420                }
01421 
01422                dx = (ix + 1.5f) - x;
01423                dy = (iy + 1.5f) - y;
01424                dist2 = dx * dx + dy * dy;
01425                if (dist2 <= rmax2) {
01426                   cover = 1.0F - (dist2 - rmin2) * cscale;
01427                   setup->quad.input.coverage[QUAD_BOTTOM_RIGHT] = MIN2(cover, 1.0f);
01428                   setup->quad.inout.mask |= MASK_BOTTOM_RIGHT;
01429                }
01430 
01431                if (setup->quad.inout.mask) {
01432                   setup->quad.input.x0 = ix;
01433                   setup->quad.input.y0 = iy;
01434                   CLIP_EMIT_QUAD(setup);
01435                }
01436             }
01437          }
01438       }
01439       else {
01440          /* square points */
01441          const int xmin = (int) (x + 0.75 - halfSize);
01442          const int ymin = (int) (y + 0.25 - halfSize);
01443          const int xmax = xmin + (int) size;
01444          const int ymax = ymin + (int) size;
01445          /* XXX could apply scissor to xmin,ymin,xmax,ymax now */
01446          const int ixmin = block(xmin);
01447          const int ixmax = block(xmax - 1);
01448          const int iymin = block(ymin);
01449          const int iymax = block(ymax - 1);
01450          int ix, iy;
01451 
01452          /*
01453          debug_printf("(%f, %f) -> X:%d..%d Y:%d..%d\n", x, y, xmin, xmax,ymin,ymax);
01454          */
01455          for (iy = iymin; iy <= iymax; iy += 2) {
01456             uint rowMask = 0xf;
01457             if (iy < ymin) {
01458                /* above the top edge */
01459                rowMask &= (MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT);
01460             }
01461             if (iy + 1 >= ymax) {
01462                /* below the bottom edge */
01463                rowMask &= (MASK_TOP_LEFT | MASK_TOP_RIGHT);
01464             }
01465 
01466             for (ix = ixmin; ix <= ixmax; ix += 2) {
01467                uint mask = rowMask;
01468 
01469                if (ix < xmin) {
01470                   /* fragment is past left edge of point, turn off left bits */
01471                   mask &= (MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT);
01472                }
01473                if (ix + 1 >= xmax) {
01474                   /* past the right edge */
01475                   mask &= (MASK_BOTTOM_LEFT | MASK_TOP_LEFT);
01476                }
01477 
01478                setup->quad.inout.mask = mask;
01479                setup->quad.input.x0 = ix;
01480                setup->quad.input.y0 = iy;
01481                CLIP_EMIT_QUAD(setup);
01482             }
01483          }
01484       }
01485    }
01486 
01487    WAIT_FOR_COMPLETION(setup);
01488 }
01489 
01490 void setup_prepare( struct setup_context *setup )
01491 {
01492    struct softpipe_context *sp = setup->softpipe;
01493    unsigned i;
01494 
01495    if (sp->dirty) {
01496       softpipe_update_derived(sp);
01497    }
01498 
01499    /* Mark surfaces as defined now */
01500    for (i = 0; i < sp->framebuffer.num_cbufs; i++){
01501       if (sp->framebuffer.cbufs[i]) {
01502          sp->framebuffer.cbufs[i]->status = PIPE_SURFACE_STATUS_DEFINED;
01503       }
01504    }
01505    if (sp->framebuffer.zsbuf) {
01506       sp->framebuffer.zsbuf->status = PIPE_SURFACE_STATUS_DEFINED;
01507    }
01508 
01509    /* Note: nr_attrs is only used for debugging (vertex printing) */
01510    setup->quad.nr_attrs = draw_num_vs_outputs(sp->draw);
01511 
01512    for (i = 0; i < SP_NUM_QUAD_THREADS; i++) {
01513       sp->quad[i].first->begin( sp->quad[i].first );
01514    }
01515 
01516    if (sp->reduced_api_prim == PIPE_PRIM_TRIANGLES &&
01517        sp->rasterizer->fill_cw == PIPE_POLYGON_MODE_FILL &&
01518        sp->rasterizer->fill_ccw == PIPE_POLYGON_MODE_FILL) {
01519       /* we'll do culling */
01520       setup->winding = sp->rasterizer->cull_mode;
01521    }
01522    else {
01523       /* 'draw' will do culling */
01524       setup->winding = PIPE_WINDING_NONE;
01525    }
01526 }
01527 
01528 
01529 
01530 void setup_destroy_context( struct setup_context *setup )
01531 {
01532    FREE( setup );
01533 }
01534 
01535 
01539 struct setup_context *setup_create_context( struct softpipe_context *softpipe )
01540 {
01541    struct setup_context *setup = CALLOC_STRUCT(setup_context);
01542 #if SP_NUM_QUAD_THREADS > 1
01543    uint i;
01544 #endif
01545 
01546    setup->softpipe = softpipe;
01547 
01548    setup->quad.coef = setup->coef;
01549    setup->quad.posCoef = &setup->posCoef;
01550 
01551 #if SP_NUM_QUAD_THREADS > 1
01552    setup->que.first = 0;
01553    setup->que.last = 0;
01554    pipe_mutex_init( setup->que.que_mutex );
01555    pipe_condvar_init( setup->que.que_notfull_condvar );
01556    pipe_condvar_init( setup->que.que_notempty_condvar );
01557    setup->que.jobs_added = 0;
01558    setup->que.jobs_done = 0;
01559    pipe_condvar_init( setup->que.que_done_condvar );
01560    for (i = 0; i < SP_NUM_QUAD_THREADS; i++) {
01561       setup->threads[i].setup = setup;
01562       setup->threads[i].id = i;
01563       setup->threads[i].handle = pipe_thread_create( quad_thread, &setup->threads[i] );
01564    }
01565 #endif
01566 
01567    return setup;
01568 }
01569 

Generated on Tue Sep 29 06:25:17 2009 for Gallium3D by  doxygen 1.5.4