Home | History | Annotate | Download | only in swrast
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included
     14  * in all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 #include "main/framebuffer.h"
     26 #include "main/glheader.h"
     27 #include "main/macros.h"
     28 #include "s_context.h"
     29 #include "s_feedback.h"
     30 #include "s_points.h"
     31 #include "s_span.h"
     32 
     33 
     34 /**
     35  * Used to cull points with invalid coords
     36  */
     37 #define CULL_INVALID(V)                              \
     38    do {                                              \
     39       float tmp = (V)->attrib[VARYING_SLOT_POS][0]   \
     40                 + (V)->attrib[VARYING_SLOT_POS][1];  \
     41       if (IS_INF_OR_NAN(tmp))                        \
     42 	 return;                                     \
     43    } while(0)
     44 
     45 
     46 
     47 /**
     48  * Get/compute the point size.
     49  * The size may come from a vertex shader, or computed with attentuation
     50  * or just the glPointSize value.
     51  * Must also clamp to user-defined range and implmentation limits.
     52  */
     53 static inline GLfloat
     54 get_size(const struct gl_context *ctx, const SWvertex *vert, GLboolean smoothed)
     55 {
     56    GLfloat size;
     57 
     58    if (ctx->Point._Attenuated || ctx->VertexProgram.PointSizeEnabled) {
     59       /* use vertex's point size */
     60       size = vert->pointSize;
     61    }
     62    else {
     63       /* use constant point size */
     64       size = ctx->Point.Size;
     65    }
     66    /* always clamp to user-specified limits */
     67    size = CLAMP(size, ctx->Point.MinSize, ctx->Point.MaxSize);
     68    /* clamp to implementation limits */
     69    if (smoothed)
     70       size = CLAMP(size, ctx->Const.MinPointSizeAA, ctx->Const.MaxPointSizeAA);
     71    else
     72       size = CLAMP(size, ctx->Const.MinPointSize, ctx->Const.MaxPointSize);
     73 
     74    return size;
     75 }
     76 
     77 
     78 /**
     79  * Draw a point sprite
     80  */
     81 static void
     82 sprite_point(struct gl_context *ctx, const SWvertex *vert)
     83 {
     84    SWcontext *swrast = SWRAST_CONTEXT(ctx);
     85    SWspan span;
     86    GLfloat size;
     87    GLuint tCoords[MAX_TEXTURE_COORD_UNITS + 1];
     88    GLuint numTcoords = 0;
     89    GLfloat t0, dtdy;
     90 
     91    CULL_INVALID(vert);
     92 
     93    /* z coord */
     94    if (ctx->DrawBuffer->Visual.depthBits <= 16)
     95       span.z = FloatToFixed(vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
     96    else
     97       span.z = (GLuint) (vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
     98    span.zStep = 0;
     99 
    100    size = get_size(ctx, vert, GL_FALSE);
    101 
    102    /* span init */
    103    INIT_SPAN(span, GL_POINT);
    104    span.interpMask = SPAN_Z | SPAN_RGBA;
    105 
    106    span.facing = swrast->PointLineFacing;
    107 
    108    span.red   = ChanToFixed(vert->color[0]);
    109    span.green = ChanToFixed(vert->color[1]);
    110    span.blue  = ChanToFixed(vert->color[2]);
    111    span.alpha = ChanToFixed(vert->color[3]);
    112    span.redStep = 0;
    113    span.greenStep = 0;
    114    span.blueStep = 0;
    115    span.alphaStep = 0;
    116 
    117    /* need these for fragment programs */
    118    span.attrStart[VARYING_SLOT_POS][3] = 1.0F;
    119    span.attrStepX[VARYING_SLOT_POS][3] = 0.0F;
    120    span.attrStepY[VARYING_SLOT_POS][3] = 0.0F;
    121 
    122    {
    123       GLfloat s, r, dsdx;
    124 
    125       /* texcoord / pointcoord interpolants */
    126       s = 0.0F;
    127       dsdx = 1.0F / size;
    128       if (ctx->Point.SpriteOrigin == GL_LOWER_LEFT) {
    129          dtdy = 1.0F / size;
    130          t0 = 0.5F * dtdy;
    131       }
    132       else {
    133          /* GL_UPPER_LEFT */
    134          dtdy = -1.0F / size;
    135          t0 = 1.0F + 0.5F * dtdy;
    136       }
    137 
    138       ATTRIB_LOOP_BEGIN
    139          if (attr >= VARYING_SLOT_TEX0 && attr <= VARYING_SLOT_TEX7) {
    140             /* a texcoord attribute */
    141             const GLuint u = attr - VARYING_SLOT_TEX0;
    142             assert(u < MAX_TEXTURE_COORD_UNITS);
    143             if (ctx->Point.CoordReplace & (1u << u)) {
    144                tCoords[numTcoords++] = attr;
    145 
    146                if (ctx->Point.SpriteRMode == GL_ZERO)
    147                   r = 0.0F;
    148                else if (ctx->Point.SpriteRMode == GL_S)
    149                   r = vert->attrib[attr][0];
    150                else /* GL_R */
    151                   r = vert->attrib[attr][2];
    152 
    153                span.attrStart[attr][0] = s;
    154                span.attrStart[attr][1] = 0.0; /* overwritten below */
    155                span.attrStart[attr][2] = r;
    156                span.attrStart[attr][3] = 1.0;
    157 
    158                span.attrStepX[attr][0] = dsdx;
    159                span.attrStepX[attr][1] = 0.0;
    160                span.attrStepX[attr][2] = 0.0;
    161                span.attrStepX[attr][3] = 0.0;
    162 
    163                span.attrStepY[attr][0] = 0.0;
    164                span.attrStepY[attr][1] = dtdy;
    165                span.attrStepY[attr][2] = 0.0;
    166                span.attrStepY[attr][3] = 0.0;
    167 
    168                continue;
    169             }
    170          }
    171          else if (attr == VARYING_SLOT_PNTC) {
    172             /* GLSL gl_PointCoord.xy (.zw undefined) */
    173             span.attrStart[VARYING_SLOT_PNTC][0] = 0.0;
    174             span.attrStart[VARYING_SLOT_PNTC][1] = 0.0; /* t0 set below */
    175             span.attrStepX[VARYING_SLOT_PNTC][0] = dsdx;
    176             span.attrStepX[VARYING_SLOT_PNTC][1] = 0.0;
    177             span.attrStepY[VARYING_SLOT_PNTC][0] = 0.0;
    178             span.attrStepY[VARYING_SLOT_PNTC][1] = dtdy;
    179             tCoords[numTcoords++] = VARYING_SLOT_PNTC;
    180             continue;
    181          }
    182          /* use vertex's texcoord/attrib */
    183          COPY_4V(span.attrStart[attr], vert->attrib[attr]);
    184          ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
    185          ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
    186       ATTRIB_LOOP_END;
    187    }
    188 
    189    /* compute pos, bounds and render */
    190    {
    191       const GLfloat x = vert->attrib[VARYING_SLOT_POS][0];
    192       const GLfloat y = vert->attrib[VARYING_SLOT_POS][1];
    193       GLint iSize = (GLint) (size + 0.5F);
    194       GLint xmin, xmax, ymin, ymax, iy;
    195       GLint iRadius;
    196       GLfloat tcoord = t0;
    197 
    198       iSize = MAX2(1, iSize);
    199       iRadius = iSize / 2;
    200 
    201       if (iSize & 1) {
    202          /* odd size */
    203          xmin = (GLint) (x - iRadius);
    204          xmax = (GLint) (x + iRadius);
    205          ymin = (GLint) (y - iRadius);
    206          ymax = (GLint) (y + iRadius);
    207       }
    208       else {
    209          /* even size */
    210          /* 0.501 factor allows conformance to pass */
    211          xmin = (GLint) (x + 0.501F) - iRadius;
    212          xmax = xmin + iSize - 1;
    213          ymin = (GLint) (y + 0.501F) - iRadius;
    214          ymax = ymin + iSize - 1;
    215       }
    216 
    217       /* render spans */
    218       for (iy = ymin; iy <= ymax; iy++) {
    219          GLuint i;
    220          /* setup texcoord T for this row */
    221          for (i = 0; i < numTcoords; i++) {
    222             span.attrStart[tCoords[i]][1] = tcoord;
    223          }
    224 
    225          /* these might get changed by span clipping */
    226          span.x = xmin;
    227          span.y = iy;
    228          span.end = xmax - xmin + 1;
    229 
    230          _swrast_write_rgba_span(ctx, &span);
    231 
    232          tcoord += dtdy;
    233       }
    234    }
    235 }
    236 
    237 
    238 /**
    239  * Draw smooth/antialiased point.  RGB or CI mode.
    240  */
    241 static void
    242 smooth_point(struct gl_context *ctx, const SWvertex *vert)
    243 {
    244    SWcontext *swrast = SWRAST_CONTEXT(ctx);
    245    SWspan span;
    246    GLfloat size, alphaAtten;
    247 
    248    CULL_INVALID(vert);
    249 
    250    /* z coord */
    251    if (ctx->DrawBuffer->Visual.depthBits <= 16)
    252       span.z = FloatToFixed(vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
    253    else
    254       span.z = (GLuint) (vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
    255    span.zStep = 0;
    256 
    257    size = get_size(ctx, vert, GL_TRUE);
    258 
    259    /* alpha attenuation / fade factor */
    260    if (_mesa_is_multisample_enabled(ctx)) {
    261       if (vert->pointSize >= ctx->Point.Threshold) {
    262          alphaAtten = 1.0F;
    263       }
    264       else {
    265          GLfloat dsize = vert->pointSize / ctx->Point.Threshold;
    266          alphaAtten = dsize * dsize;
    267       }
    268    }
    269    else {
    270       alphaAtten = 1.0;
    271    }
    272    (void) alphaAtten; /* not used */
    273 
    274    /* span init */
    275    INIT_SPAN(span, GL_POINT);
    276    span.interpMask = SPAN_Z | SPAN_RGBA;
    277    span.arrayMask = SPAN_COVERAGE | SPAN_MASK;
    278 
    279    span.facing = swrast->PointLineFacing;
    280 
    281    span.red   = ChanToFixed(vert->color[0]);
    282    span.green = ChanToFixed(vert->color[1]);
    283    span.blue  = ChanToFixed(vert->color[2]);
    284    span.alpha = ChanToFixed(vert->color[3]);
    285    span.redStep = 0;
    286    span.greenStep = 0;
    287    span.blueStep = 0;
    288    span.alphaStep = 0;
    289 
    290    /* need these for fragment programs */
    291    span.attrStart[VARYING_SLOT_POS][3] = 1.0F;
    292    span.attrStepX[VARYING_SLOT_POS][3] = 0.0F;
    293    span.attrStepY[VARYING_SLOT_POS][3] = 0.0F;
    294 
    295    ATTRIB_LOOP_BEGIN
    296       COPY_4V(span.attrStart[attr], vert->attrib[attr]);
    297       ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
    298       ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
    299    ATTRIB_LOOP_END
    300 
    301    /* compute pos, bounds and render */
    302    {
    303       const GLfloat x = vert->attrib[VARYING_SLOT_POS][0];
    304       const GLfloat y = vert->attrib[VARYING_SLOT_POS][1];
    305       const GLfloat radius = 0.5F * size;
    306       const GLfloat rmin = radius - 0.7071F;  /* 0.7071 = sqrt(2)/2 */
    307       const GLfloat rmax = radius + 0.7071F;
    308       const GLfloat rmin2 = MAX2(0.0F, rmin * rmin);
    309       const GLfloat rmax2 = rmax * rmax;
    310       const GLfloat cscale = 1.0F / (rmax2 - rmin2);
    311       const GLint xmin = (GLint) (x - radius);
    312       const GLint xmax = (GLint) (x + radius);
    313       const GLint ymin = (GLint) (y - radius);
    314       const GLint ymax = (GLint) (y + radius);
    315       GLint ix, iy;
    316 
    317       for (iy = ymin; iy <= ymax; iy++) {
    318 
    319          /* these might get changed by span clipping */
    320          span.x = xmin;
    321          span.y = iy;
    322          span.end = xmax - xmin + 1;
    323 
    324          /* compute coverage for each pixel in span */
    325          for (ix = xmin; ix <= xmax; ix++) {
    326             const GLfloat dx = ix - x + 0.5F;
    327             const GLfloat dy = iy - y + 0.5F;
    328             const GLfloat dist2 = dx * dx + dy * dy;
    329             GLfloat coverage;
    330 
    331             if (dist2 < rmax2) {
    332                if (dist2 >= rmin2) {
    333                   /* compute partial coverage */
    334                   coverage = 1.0F - (dist2 - rmin2) * cscale;
    335                }
    336                else {
    337                   /* full coverage */
    338                   coverage = 1.0F;
    339                }
    340                span.array->mask[ix - xmin] = 1;
    341             }
    342             else {
    343                /* zero coverage - fragment outside the radius */
    344                coverage = 0.0;
    345                span.array->mask[ix - xmin] = 0;
    346             }
    347             span.array->coverage[ix - xmin] = coverage;
    348          }
    349 
    350          /* render span */
    351          _swrast_write_rgba_span(ctx, &span);
    352 
    353       }
    354    }
    355 }
    356 
    357 
    358 /**
    359  * Draw large (size >= 1) non-AA point.  RGB or CI mode.
    360  */
    361 static void
    362 large_point(struct gl_context *ctx, const SWvertex *vert)
    363 {
    364    SWcontext *swrast = SWRAST_CONTEXT(ctx);
    365    SWspan span;
    366    GLfloat size;
    367 
    368    CULL_INVALID(vert);
    369 
    370    /* z coord */
    371    if (ctx->DrawBuffer->Visual.depthBits <= 16)
    372       span.z = FloatToFixed(vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
    373    else
    374       span.z = (GLuint) (vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
    375    span.zStep = 0;
    376 
    377    size = get_size(ctx, vert, GL_FALSE);
    378 
    379    /* span init */
    380    INIT_SPAN(span, GL_POINT);
    381    span.arrayMask = SPAN_XY;
    382    span.facing = swrast->PointLineFacing;
    383 
    384    span.interpMask = SPAN_Z | SPAN_RGBA;
    385    span.red   = ChanToFixed(vert->color[0]);
    386    span.green = ChanToFixed(vert->color[1]);
    387    span.blue  = ChanToFixed(vert->color[2]);
    388    span.alpha = ChanToFixed(vert->color[3]);
    389    span.redStep = 0;
    390    span.greenStep = 0;
    391    span.blueStep = 0;
    392    span.alphaStep = 0;
    393 
    394    /* need these for fragment programs */
    395    span.attrStart[VARYING_SLOT_POS][3] = 1.0F;
    396    span.attrStepX[VARYING_SLOT_POS][3] = 0.0F;
    397    span.attrStepY[VARYING_SLOT_POS][3] = 0.0F;
    398 
    399    ATTRIB_LOOP_BEGIN
    400       COPY_4V(span.attrStart[attr], vert->attrib[attr]);
    401       ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
    402       ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
    403    ATTRIB_LOOP_END
    404 
    405    /* compute pos, bounds and render */
    406    {
    407       const GLfloat x = vert->attrib[VARYING_SLOT_POS][0];
    408       const GLfloat y = vert->attrib[VARYING_SLOT_POS][1];
    409       GLint iSize = (GLint) (size + 0.5F);
    410       GLint xmin, xmax, ymin, ymax, ix, iy;
    411       GLint iRadius;
    412 
    413       iSize = MAX2(1, iSize);
    414       iRadius = iSize / 2;
    415 
    416       if (iSize & 1) {
    417          /* odd size */
    418          xmin = (GLint) (x - iRadius);
    419          xmax = (GLint) (x + iRadius);
    420          ymin = (GLint) (y - iRadius);
    421          ymax = (GLint) (y + iRadius);
    422       }
    423       else {
    424          /* even size */
    425          /* 0.501 factor allows conformance to pass */
    426          xmin = (GLint) (x + 0.501F) - iRadius;
    427          xmax = xmin + iSize - 1;
    428          ymin = (GLint) (y + 0.501F) - iRadius;
    429          ymax = ymin + iSize - 1;
    430       }
    431 
    432       /* generate fragments */
    433       span.end = 0;
    434       for (iy = ymin; iy <= ymax; iy++) {
    435          for (ix = xmin; ix <= xmax; ix++) {
    436             span.array->x[span.end] = ix;
    437             span.array->y[span.end] = iy;
    438             span.end++;
    439          }
    440       }
    441       assert(span.end <= SWRAST_MAX_WIDTH);
    442       _swrast_write_rgba_span(ctx, &span);
    443    }
    444 }
    445 
    446 
    447 /**
    448  * Draw size=1, single-pixel point
    449  */
    450 static void
    451 pixel_point(struct gl_context *ctx, const SWvertex *vert)
    452 {
    453    SWcontext *swrast = SWRAST_CONTEXT(ctx);
    454    /*
    455     * Note that unlike the other functions, we put single-pixel points
    456     * into a special span array in order to render as many points as
    457     * possible with a single _swrast_write_rgba_span() call.
    458     */
    459    SWspan *span = &(swrast->PointSpan);
    460    GLuint count;
    461 
    462    CULL_INVALID(vert);
    463 
    464    /* Span init */
    465    span->interpMask = 0;
    466    span->arrayMask = SPAN_XY | SPAN_Z;
    467    span->arrayMask |= SPAN_RGBA;
    468    /*span->arrayMask |= SPAN_LAMBDA;*/
    469    span->arrayAttribs = swrast->_ActiveAttribMask; /* we'll produce these vals */
    470 
    471    /* need these for fragment programs */
    472    span->attrStart[VARYING_SLOT_POS][3] = 1.0F;
    473    span->attrStepX[VARYING_SLOT_POS][3] = 0.0F;
    474    span->attrStepY[VARYING_SLOT_POS][3] = 0.0F;
    475 
    476    /* check if we need to flush */
    477    if (span->end >= SWRAST_MAX_WIDTH ||
    478        (swrast->_RasterMask & (BLEND_BIT | LOGIC_OP_BIT | MASKING_BIT)) ||
    479        span->facing != swrast->PointLineFacing) {
    480       if (span->end > 0) {
    481 	 _swrast_write_rgba_span(ctx, span);
    482          span->end = 0;
    483       }
    484    }
    485 
    486    count = span->end;
    487 
    488    span->facing = swrast->PointLineFacing;
    489 
    490    /* fragment attributes */
    491    span->array->rgba[count][RCOMP] = vert->color[0];
    492    span->array->rgba[count][GCOMP] = vert->color[1];
    493    span->array->rgba[count][BCOMP] = vert->color[2];
    494    span->array->rgba[count][ACOMP] = vert->color[3];
    495 
    496    ATTRIB_LOOP_BEGIN
    497       COPY_4V(span->array->attribs[attr][count], vert->attrib[attr]);
    498    ATTRIB_LOOP_END
    499 
    500    /* fragment position */
    501    span->array->x[count] = (GLint) vert->attrib[VARYING_SLOT_POS][0];
    502    span->array->y[count] = (GLint) vert->attrib[VARYING_SLOT_POS][1];
    503    span->array->z[count] = (GLint) (vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
    504 
    505    span->end = count + 1;
    506    assert(span->end <= SWRAST_MAX_WIDTH);
    507 }
    508 
    509 
    510 /**
    511  * Add specular color to primary color, draw point, restore original
    512  * primary color.
    513  */
    514 void
    515 _swrast_add_spec_terms_point(struct gl_context *ctx, const SWvertex *v0)
    516 {
    517    SWvertex *ncv0 = (SWvertex *) v0; /* cast away const */
    518    GLfloat rSum, gSum, bSum;
    519    GLchan cSave[4];
    520 
    521    /* save */
    522    COPY_CHAN4(cSave, ncv0->color);
    523    /* sum */
    524    rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[VARYING_SLOT_COL1][0];
    525    gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[VARYING_SLOT_COL1][1];
    526    bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[VARYING_SLOT_COL1][2];
    527    UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum);
    528    UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum);
    529    UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum);
    530    /* draw */
    531    SWRAST_CONTEXT(ctx)->SpecPoint(ctx, ncv0);
    532    /* restore */
    533    COPY_CHAN4(ncv0->color, cSave);
    534 }
    535 
    536 
    537 /**
    538  * Examine current state to determine which point drawing function to use.
    539  */
    540 void
    541 _swrast_choose_point(struct gl_context *ctx)
    542 {
    543    SWcontext *swrast = SWRAST_CONTEXT(ctx);
    544    const GLfloat size = CLAMP(ctx->Point.Size,
    545                               ctx->Point.MinSize,
    546                               ctx->Point.MaxSize);
    547 
    548    if (ctx->RenderMode == GL_RENDER) {
    549       if (ctx->Point.PointSprite) {
    550          swrast->Point = sprite_point;
    551       }
    552       else if (ctx->Point.SmoothFlag) {
    553          swrast->Point = smooth_point;
    554       }
    555       else if (size > 1.0F ||
    556                ctx->Point._Attenuated ||
    557                ctx->VertexProgram.PointSizeEnabled) {
    558          swrast->Point = large_point;
    559       }
    560       else {
    561          swrast->Point = pixel_point;
    562       }
    563    }
    564    else if (ctx->RenderMode == GL_FEEDBACK) {
    565       swrast->Point = _swrast_feedback_point;
    566    }
    567    else {
    568       /* GL_SELECT mode */
    569       swrast->Point = _swrast_select_point;
    570    }
    571 }
    572