Пример #1
0
/*
 * Clip points but ignore the first 4 (xy) clip planes.
 * (Because the generated clip mask is completely unaffacted by guard band,
 * we still need to manually evaluate the x/y planes if they are outside
 * the guard band and not just outside the vp.)
 */
static void
clip_point_guard_xy( struct draw_stage *stage,
                     struct prim_header *header )
{
   unsigned clipmask = header->v[0]->clipmask;
   if ((clipmask & 0xffffffff) == 0)
      stage->next->point(stage->next, header);
   else if ((clipmask & 0xfffffff0) == 0) {
      while (clipmask) {
         const unsigned plane_idx = ffs(clipmask)-1;
         clipmask &= ~(1 << plane_idx);  /* turn off this plane's bit */
         /* TODO: this should really do proper guardband clipping,
          * currently just throw out infs/nans.
          * Also note that vertices with negative w values MUST be tossed
          * out (not sure if proper guardband clipping would do this
          * automatically). These would usually be captured by depth clip
          * too but this can be disabled.
          */
         if (header->v[0]->clip[3] <= 0.0f ||
             util_is_inf_or_nan(header->v[0]->clip[0]) ||
             util_is_inf_or_nan(header->v[0]->clip[1]))
            return;
      }
      stage->next->point(stage->next, header);
   }
}
Пример #2
0
/*#define DEBUG_INPUTS 1*/
static void draw_fetch_gs_input(struct draw_geometry_shader *shader,
                                unsigned *indices,
                                unsigned num_vertices,
                                unsigned prim_idx)
{
   struct tgsi_exec_machine *machine = shader->machine;
   unsigned slot, vs_slot, i;
   unsigned input_vertex_stride = shader->input_vertex_stride;
   const float (*input_ptr)[4];

   input_ptr = shader->input;

   for (i = 0; i < num_vertices; ++i) {
      const float (*input)[4];
#if DEBUG_INPUTS
      debug_printf("%d) vertex index = %d (prim idx = %d)\n",
                   i, indices[i], prim_idx);
#endif
      input = (const float (*)[4])(
         (const char *)input_ptr + (indices[i] * input_vertex_stride));
      for (slot = 0, vs_slot = 0; slot < shader->info.num_inputs; ++slot) {
         unsigned idx = i * TGSI_EXEC_MAX_INPUT_ATTRIBS + slot;
         if (shader->info.input_semantic_name[slot] == TGSI_SEMANTIC_PRIMID) {
            machine->Inputs[idx].xyzw[0].f[prim_idx] =
               (float)shader->in_prim_idx;
            machine->Inputs[idx].xyzw[1].f[prim_idx] =
               (float)shader->in_prim_idx;
            machine->Inputs[idx].xyzw[2].f[prim_idx] =
               (float)shader->in_prim_idx;
            machine->Inputs[idx].xyzw[3].f[prim_idx] =
               (float)shader->in_prim_idx;
         } else {
#if DEBUG_INPUTS
            debug_printf("\tSlot = %d, vs_slot = %d, idx = %d:\n",
                         slot, vs_slot, idx);
#endif
#if 1
            assert(!util_is_inf_or_nan(input[vs_slot][0]));
            assert(!util_is_inf_or_nan(input[vs_slot][1]));
            assert(!util_is_inf_or_nan(input[vs_slot][2]));
            assert(!util_is_inf_or_nan(input[vs_slot][3]));
#endif
            machine->Inputs[idx].xyzw[0].f[prim_idx] = input[vs_slot][0];
            machine->Inputs[idx].xyzw[1].f[prim_idx] = input[vs_slot][1];
            machine->Inputs[idx].xyzw[2].f[prim_idx] = input[vs_slot][2];
            machine->Inputs[idx].xyzw[3].f[prim_idx] = input[vs_slot][3];
#if DEBUG_INPUTS
            debug_printf("\t\t%f %f %f %f\n",
                         machine->Inputs[idx].xyzw[0].f[prim_idx],
                         machine->Inputs[idx].xyzw[1].f[prim_idx],
                         machine->Inputs[idx].xyzw[2].f[prim_idx],
                         machine->Inputs[idx].xyzw[3].f[prim_idx]);
#endif
            ++vs_slot;
         }
      }
   }
}
Пример #3
0
static void print_vertex(const struct setup_context *setup,
                         const float (*v)[4])
{
   int i;
   debug_printf("   Vertex: (%p)\n", (void *) v);
   for (i = 0; i < setup->nr_vertex_attrs; i++) {
      debug_printf("     %d: %f %f %f %f\n",  i,
              v[i][0], v[i][1], v[i][2], v[i][3]);
      if (util_is_inf_or_nan(v[i][0])) {
         debug_printf("   NaN!\n");
      }
   }
}
Пример #4
0
/*#define DEBUG_OUTPUTS 1*/
static void
tgsi_fetch_gs_outputs(struct draw_geometry_shader *shader,
                      unsigned num_primitives,
                      float (**p_output)[4])
{
   struct tgsi_exec_machine *machine = shader->machine;
   unsigned prim_idx, j, slot;
   unsigned current_idx = 0;
   float (*output)[4];

   output = *p_output;

   /* Unswizzle all output results.
    */

   for (prim_idx = 0; prim_idx < num_primitives; ++prim_idx) {
      unsigned num_verts_per_prim = machine->Primitives[prim_idx];
      shader->primitive_lengths[prim_idx +   shader->emitted_primitives] =
         machine->Primitives[prim_idx];
      shader->emitted_vertices += num_verts_per_prim;
      for (j = 0; j < num_verts_per_prim; j++, current_idx++) {
         int idx = current_idx * shader->info.num_outputs;
#ifdef DEBUG_OUTPUTS
         debug_printf("%d) Output vert:\n", idx / shader->info.num_outputs);
#endif
         for (slot = 0; slot < shader->info.num_outputs; slot++) {
            output[slot][0] = machine->Outputs[idx + slot].xyzw[0].f[0];
            output[slot][1] = machine->Outputs[idx + slot].xyzw[1].f[0];
            output[slot][2] = machine->Outputs[idx + slot].xyzw[2].f[0];
            output[slot][3] = machine->Outputs[idx + slot].xyzw[3].f[0];
#ifdef DEBUG_OUTPUTS
            debug_printf("\t%d: %f %f %f %f\n", slot,
                         output[slot][0],
                         output[slot][1],
                         output[slot][2],
                         output[slot][3]);
#endif
            debug_assert(!util_is_inf_or_nan(output[slot][0]));
         }
         output = (float (*)[4])((char *)output + shader->vertex_size);
      }
   }
   *p_output = output;
   shader->emitted_primitives += num_primitives;
}
Пример #5
0
static void
llvm_fetch_gs_input(struct draw_geometry_shader *shader,
                    unsigned *indices,
                    unsigned num_vertices,
                    unsigned prim_idx)
{
   unsigned slot, i;
   int vs_slot;
   unsigned input_vertex_stride = shader->input_vertex_stride;
   const float (*input_ptr)[4];
   float (*input_data)[6][PIPE_MAX_SHADER_INPUTS][TGSI_NUM_CHANNELS][TGSI_NUM_CHANNELS] = &shader->gs_input->data;

   shader->llvm_prim_ids[shader->fetched_prim_count] =
      shader->in_prim_idx;

   input_ptr = shader->input;

   for (i = 0; i < num_vertices; ++i) {
      const float (*input)[4];
#if DEBUG_INPUTS
      debug_printf("%d) vertex index = %d (prim idx = %d)\n",
                   i, indices[i], prim_idx);
#endif
      input = (const float (*)[4])(
         (const char *)input_ptr + (indices[i] * input_vertex_stride));
      for (slot = 0, vs_slot = 0; slot < shader->info.num_inputs; ++slot) {
         if (shader->info.input_semantic_name[slot] == TGSI_SEMANTIC_PRIMID) {
            /* skip. we handle system values through gallivm */
         } else {
            vs_slot = draw_gs_get_input_index(
               shader->info.input_semantic_name[slot],
               shader->info.input_semantic_index[slot],
               shader->input_info);
            if (vs_slot < 0) {
               debug_printf("VS/GS signature mismatch!\n");
               (*input_data)[i][slot][0][prim_idx] = 0;
               (*input_data)[i][slot][1][prim_idx] = 0;
               (*input_data)[i][slot][2][prim_idx] = 0;
               (*input_data)[i][slot][3][prim_idx] = 0;
            } else {
#if DEBUG_INPUTS
               debug_printf("\tSlot = %d, vs_slot = %d, i = %d:\n",
                            slot, vs_slot, i);
               assert(!util_is_inf_or_nan(input[vs_slot][0]));
               assert(!util_is_inf_or_nan(input[vs_slot][1]));
               assert(!util_is_inf_or_nan(input[vs_slot][2]));
               assert(!util_is_inf_or_nan(input[vs_slot][3]));
#endif
               (*input_data)[i][slot][0][prim_idx] = input[vs_slot][0];
               (*input_data)[i][slot][1][prim_idx] = input[vs_slot][1];
               (*input_data)[i][slot][2][prim_idx] = input[vs_slot][2];
               (*input_data)[i][slot][3][prim_idx] = input[vs_slot][3];
#if DEBUG_INPUTS
               debug_printf("\t\t%f %f %f %f\n",
                            (*input_data)[i][slot][0][prim_idx],
                            (*input_data)[i][slot][1][prim_idx],
                            (*input_data)[i][slot][2][prim_idx],
                            (*input_data)[i][slot][3][prim_idx]);
#endif
               ++vs_slot;
            }
         }
      }
   }
}
Пример #6
0
/**
 * Compute the setup->coef[] array dadx, dady, a0 values.
 * Must be called after setup->vmin,vmax are initialized.
 */
static boolean
setup_line_coefficients(struct setup_context *setup,
                        const float (*v0)[4],
                        const float (*v1)[4])
{
   struct softpipe_context *softpipe = setup->softpipe;
   const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info;
   const struct sp_setup_info *sinfo = &softpipe->setup_info;
   uint fragSlot;
   float area;
   float v[2];

   assert(sinfo->valid);

   /* use setup->vmin, vmax to point to vertices */
   if (softpipe->rasterizer->flatshade_first)
      setup->vprovoke = v0;
   else
      setup->vprovoke = v1;
   setup->vmin = v0;
   setup->vmax = v1;

   setup->emaj.dx = setup->vmax[0][0] - setup->vmin[0][0];
   setup->emaj.dy = setup->vmax[0][1] - setup->vmin[0][1];

   /* NOTE: this is not really area but something proportional to it */
   area = setup->emaj.dx * setup->emaj.dx + setup->emaj.dy * setup->emaj.dy;
   if (area == 0.0f || util_is_inf_or_nan(area))
      return FALSE;
   setup->oneoverarea = 1.0f / area;

   /* z and w are done by linear interpolation:
    */
   v[0] = setup->vmin[0][2];
   v[1] = setup->vmax[0][2];
   line_linear_coeff(setup, &setup->posCoef, 2, v);

   v[0] = setup->vmin[0][3];
   v[1] = setup->vmax[0][3];
   line_linear_coeff(setup, &setup->posCoef, 3, v);

   /* setup interpolation for all the remaining attributes:
    */
   for (fragSlot = 0; fragSlot < fsInfo->num_inputs; fragSlot++) {
      const uint vertSlot = sinfo->attrib[fragSlot].src_index;
      uint j;

      switch (sinfo->attrib[fragSlot].interp) {
      case SP_INTERP_CONSTANT:
         for (j = 0; j < TGSI_NUM_CHANNELS; j++)
            const_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
         break;
      case SP_INTERP_LINEAR:
         for (j = 0; j < TGSI_NUM_CHANNELS; j++) {
            line_apply_cylindrical_wrap(setup->vmin[vertSlot][j],
                                        setup->vmax[vertSlot][j],
                                        fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j),
                                        v);
            line_linear_coeff(setup, &setup->coef[fragSlot], j, v);
         }
         break;
      case SP_INTERP_PERSPECTIVE:
         for (j = 0; j < TGSI_NUM_CHANNELS; j++) {
            line_apply_cylindrical_wrap(setup->vmin[vertSlot][j],
                                        setup->vmax[vertSlot][j],
                                        fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j),
                                        v);
            line_persp_coeff(setup, &setup->coef[fragSlot], j, v);
         }
         break;
      case SP_INTERP_POS:
         setup_fragcoord_coeff(setup, fragSlot);
         break;
      default:
         assert(0);
      }

      if (fsInfo->input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
         /* convert 0 to 1.0 and 1 to -1.0 */
         setup->coef[fragSlot].a0[0] = setup->facing * -2.0f + 1.0f;
         setup->coef[fragSlot].dadx[0] = 0.0;
         setup->coef[fragSlot].dady[0] = 0.0;
      }
   }
   return TRUE;
}
Пример #7
0
/**
 * Sort the vertices from top to bottom order, setting up the triangle
 * edge fields (ebot, emaj, etop).
 * \return FALSE if coords are inf/nan (cull the tri), TRUE otherwise
 */
static boolean
setup_sort_vertices(struct setup_context *setup,
                    float det,
                    const float (*v0)[4],
                    const float (*v1)[4],
                    const float (*v2)[4])
{
   if (setup->softpipe->rasterizer->flatshade_first)
      setup->vprovoke = v0;
   else
      setup->vprovoke = v2;

   /* determine bottom to top order of vertices */
   {
      float y0 = v0[0][1];
      float y1 = v1[0][1];
      float y2 = v2[0][1];
      if (y0 <= y1) {
	 if (y1 <= y2) {
	    /* y0<=y1<=y2 */
	    setup->vmin = v0;
	    setup->vmid = v1;
	    setup->vmax = v2;
	 }
	 else if (y2 <= y0) {
	    /* y2<=y0<=y1 */
	    setup->vmin = v2;
	    setup->vmid = v0;
	    setup->vmax = v1;
	 }
	 else {
	    /* y0<=y2<=y1 */
	    setup->vmin = v0;
	    setup->vmid = v2;
	    setup->vmax = v1;
	 }
      }
      else {
	 if (y0 <= y2) {
	    /* y1<=y0<=y2 */
	    setup->vmin = v1;
	    setup->vmid = v0;
	    setup->vmax = v2;
	 }
	 else if (y2 <= y1) {
	    /* y2<=y1<=y0 */
	    setup->vmin = v2;
	    setup->vmid = v1;
	    setup->vmax = v0;
	 }
	 else {
	    /* y1<=y2<=y0 */
	    setup->vmin = v1;
	    setup->vmid = v2;
	    setup->vmax = v0;
	 }
      }
   }

   setup->ebot.dx = setup->vmid[0][0] - setup->vmin[0][0];
   setup->ebot.dy = setup->vmid[0][1] - setup->vmin[0][1];
   setup->emaj.dx = setup->vmax[0][0] - setup->vmin[0][0];
   setup->emaj.dy = setup->vmax[0][1] - setup->vmin[0][1];
   setup->etop.dx = setup->vmax[0][0] - setup->vmid[0][0];
   setup->etop.dy = setup->vmax[0][1] - setup->vmid[0][1];

   /*
    * Compute triangle's area.  Use 1/area to compute partial
    * derivatives of attributes later.
    *
    * The area will be the same as prim->det, but the sign may be
    * different depending on how the vertices get sorted above.
    *
    * To determine whether the primitive is front or back facing we
    * use the prim->det value because its sign is correct.
    */
   {
      const float area = (setup->emaj.dx * setup->ebot.dy -
			    setup->ebot.dx * setup->emaj.dy);

      setup->oneoverarea = 1.0f / area;

      /*
      debug_printf("%s one-over-area %f  area %f  det %f\n",
                   __FUNCTION__, setup->oneoverarea, area, det );
      */
      if (util_is_inf_or_nan(setup->oneoverarea))
         return FALSE;
   }

   /* We need to know if this is a front or back-facing triangle for:
    *  - the GLSL gl_FrontFacing fragment attribute (bool)
    *  - two-sided stencil test
    * 0 = front-facing, 1 = back-facing
    */
   setup->facing = 
      ((det < 0.0) ^ 
       (setup->softpipe->rasterizer->front_ccw));

   {
      unsigned face = setup->facing == 0 ? PIPE_FACE_FRONT : PIPE_FACE_BACK;

      if (face & setup->cull_face)
	 return FALSE;
   }

   return TRUE;
}
Пример #8
0
/**
 * Compute the setup->coef[] array dadx, dady, a0 values.
 * Must be called after setup->vmin,vmax are initialized.
 */
static INLINE boolean
setup_line_coefficients(struct setup_context *setup,
                        const float (*v0)[4],
                        const float (*v1)[4])
{
   struct softpipe_context *softpipe = setup->softpipe;
   const struct sp_fragment_shader *spfs = softpipe->fs;
   const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe);
   uint fragSlot;
   float area;

   /* use setup->vmin, vmax to point to vertices */
   if (softpipe->rasterizer->flatshade_first)
      setup->vprovoke = v0;
   else
      setup->vprovoke = v1;
   setup->vmin = v0;
   setup->vmax = v1;

   setup->emaj.dx = setup->vmax[0][0] - setup->vmin[0][0];
   setup->emaj.dy = setup->vmax[0][1] - setup->vmin[0][1];

   /* NOTE: this is not really area but something proportional to it */
   area = setup->emaj.dx * setup->emaj.dx + setup->emaj.dy * setup->emaj.dy;
   if (area == 0.0f || util_is_inf_or_nan(area))
      return FALSE;
   setup->oneoverarea = 1.0f / area;

   /* z and w are done by linear interpolation:
    */
   line_linear_coeff(setup, &setup->posCoef, 0, 2);
   line_linear_coeff(setup, &setup->posCoef, 0, 3);

   /* setup interpolation for all the remaining attributes:
    */
   for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) {
      const uint vertSlot = vinfo->attrib[fragSlot].src_index;
      uint j;

      switch (vinfo->attrib[fragSlot].interp_mode) {
      case INTERP_CONSTANT:
         for (j = 0; j < NUM_CHANNELS; j++)
            const_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
         break;
      case INTERP_LINEAR:
         for (j = 0; j < NUM_CHANNELS; j++)
            line_linear_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
         break;
      case INTERP_PERSPECTIVE:
         for (j = 0; j < NUM_CHANNELS; j++)
            line_persp_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
         break;
      case INTERP_POS:
         setup_fragcoord_coeff(setup, fragSlot);
         break;
      default:
         assert(0);
      }

      if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
         setup->coef[fragSlot].a0[0] = 1.0f - setup->facing;
         setup->coef[fragSlot].dadx[0] = 0.0;
         setup->coef[fragSlot].dady[0] = 0.0;
      }
   }
   return TRUE;
}
Пример #9
0
/**
 * Sort the vertices from top to bottom order, setting up the triangle
 * edge fields (ebot, emaj, etop).
 * \return FALSE if coords are inf/nan (cull the tri), TRUE otherwise
 */
static boolean setup_sort_vertices( struct setup_context *setup,
                                    float det,
                                    const float (*v0)[4],
                                    const float (*v1)[4],
                                    const float (*v2)[4] )
{
   setup->vprovoke = v2;

   /* determine bottom to top order of vertices */
   {
      float y0 = v0[0][1];
      float y1 = v1[0][1];
      float y2 = v2[0][1];
      if (y0 <= y1) {
	 if (y1 <= y2) {
	    /* y0<=y1<=y2 */
	    setup->vmin = v0;
	    setup->vmid = v1;
	    setup->vmax = v2;
	 }
	 else if (y2 <= y0) {
	    /* y2<=y0<=y1 */
	    setup->vmin = v2;
	    setup->vmid = v0;
	    setup->vmax = v1;
	 }
	 else {
	    /* y0<=y2<=y1 */
	    setup->vmin = v0;
	    setup->vmid = v2;
	    setup->vmax = v1;
	 }
      }
      else {
	 if (y0 <= y2) {
	    /* y1<=y0<=y2 */
	    setup->vmin = v1;
	    setup->vmid = v0;
	    setup->vmax = v2;
	 }
	 else if (y2 <= y1) {
	    /* y2<=y1<=y0 */
	    setup->vmin = v2;
	    setup->vmid = v1;
	    setup->vmax = v0;
	 }
	 else {
	    /* y1<=y2<=y0 */
	    setup->vmin = v1;
	    setup->vmid = v2;
	    setup->vmax = v0;
	 }
      }
   }

   setup->ebot.dx = setup->vmid[0][0] - setup->vmin[0][0];
   setup->ebot.dy = setup->vmid[0][1] - setup->vmin[0][1];
   setup->emaj.dx = setup->vmax[0][0] - setup->vmin[0][0];
   setup->emaj.dy = setup->vmax[0][1] - setup->vmin[0][1];
   setup->etop.dx = setup->vmax[0][0] - setup->vmid[0][0];
   setup->etop.dy = setup->vmax[0][1] - setup->vmid[0][1];

   /*
    * Compute triangle's area.  Use 1/area to compute partial
    * derivatives of attributes later.
    *
    * The area will be the same as prim->det, but the sign may be
    * different depending on how the vertices get sorted above.
    *
    * To determine whether the primitive is front or back facing we
    * use the prim->det value because its sign is correct.
    */
   {
      const float area = (setup->emaj.dx * setup->ebot.dy -
			    setup->ebot.dx * setup->emaj.dy);

      setup->oneoverarea = 1.0f / area;

      /*
      debug_printf("%s one-over-area %f  area %f  det %f\n",
                   __FUNCTION__, setup->oneoverarea, area, det );
      */
      if (util_is_inf_or_nan(setup->oneoverarea))
         return FALSE;
   }

   /* We need to know if this is a front or back-facing triangle for:
    *  - the GLSL gl_FrontFacing fragment attribute (bool)
    *  - two-sided stencil test
    */
   setup->facing = 
      ((det > 0.0) ^ 
       (setup->softpipe->rasterizer->front_winding == PIPE_WINDING_CW));

   /* Prepare pixel offset for rasterisation:
    *  - pixel center (0.5, 0.5) for GL, or
    *  - assume (0.0, 0.0) for other APIs.
    */
   if (setup->softpipe->rasterizer->gl_rasterization_rules) {
      setup->pixel_offset = 0.5f;
   } else {
      setup->pixel_offset = 0.0f;
   }

   return TRUE;
}
Пример #10
0
/* Clip a line against the viewport and user clip planes.
 */
static void
do_clip_line( struct draw_stage *stage,
	      struct prim_header *header,
	      unsigned clipmask )
{
   const struct clip_stage *clipper = clip_stage( stage );
   struct vertex_header *v0 = header->v[0];
   struct vertex_header *v1 = header->v[1];
   float t0 = 0.0F;
   float t1 = 0.0F;
   struct prim_header newprim;
   int viewport_index = draw_viewport_index(clipper->stage.draw, v0);

   while (clipmask) {
      const unsigned plane_idx = ffs(clipmask)-1;
      const float dp0 = getclipdist(clipper, v0, plane_idx);
      const float dp1 = getclipdist(clipper, v1, plane_idx);

      if (util_is_inf_or_nan(dp0) || util_is_inf_or_nan(dp1))
         return; //discard nan

      if (dp1 < 0.0F) {
	 float t = dp1 / (dp1 - dp0);
         t1 = MAX2(t1, t);
      } 

      if (dp0 < 0.0F) {
	 float t = dp0 / (dp0 - dp1);
         t0 = MAX2(t0, t);
      }

      if (t0 + t1 >= 1.0F)
	 return; /* discard */

      clipmask &= ~(1 << plane_idx);  /* turn off this plane's bit */
   }

   if (v0->clipmask) {
      interp( clipper, stage->tmp[0], t0, v0, v1, viewport_index );
      if (stage->draw->rasterizer->flatshade_first) {
         copy_flat(stage, stage->tmp[0], v0);  /* copy v0 color to tmp[0] */
      }
      else {
         copy_flat(stage, stage->tmp[0], v1);  /* copy v1 color to tmp[0] */
      }
      newprim.v[0] = stage->tmp[0];
   }
   else {
      newprim.v[0] = v0;
   }

   if (v1->clipmask) {
      interp( clipper, stage->tmp[1], t1, v1, v0, viewport_index );
      if (stage->draw->rasterizer->flatshade_first) {
         copy_flat(stage, stage->tmp[1], v0);  /* copy v0 color to tmp[1] */
      }
      else {
         copy_flat(stage, stage->tmp[1], v1);  /* copy v1 color to tmp[1] */
      }
      newprim.v[1] = stage->tmp[1];
   }
   else {
      newprim.v[1] = v1;
   }

   stage->next->line( stage->next, &newprim );
}
Пример #11
0
/* Clip a triangle against the viewport and user clip planes.
 */
static void
do_clip_tri( struct draw_stage *stage, 
	     struct prim_header *header,
	     unsigned clipmask )
{
   struct clip_stage *clipper = clip_stage( stage );
   struct vertex_header *a[MAX_CLIPPED_VERTICES];
   struct vertex_header *b[MAX_CLIPPED_VERTICES];
   struct vertex_header **inlist = a;
   struct vertex_header **outlist = b;
   unsigned tmpnr = 0;
   unsigned n = 3;
   unsigned i;
   boolean aEdges[MAX_CLIPPED_VERTICES];
   boolean bEdges[MAX_CLIPPED_VERTICES];
   boolean *inEdges = aEdges;
   boolean *outEdges = bEdges;
   int viewport_index = 0;

   inlist[0] = header->v[0];
   inlist[1] = header->v[1];
   inlist[2] = header->v[2];

   viewport_index = draw_viewport_index(clipper->stage.draw, inlist[0]);

   if (DEBUG_CLIP) {
      const float *v0 = header->v[0]->clip;
      const float *v1 = header->v[1]->clip;
      const float *v2 = header->v[2]->clip;
      debug_printf("Clip triangle:\n");
      debug_printf(" %f, %f, %f, %f\n", v0[0], v0[1], v0[2], v0[3]);
      debug_printf(" %f, %f, %f, %f\n", v1[0], v1[1], v1[2], v1[3]);
      debug_printf(" %f, %f, %f, %f\n", v2[0], v2[1], v2[2], v2[3]);
   }

   /*
    * Note: at this point we can't just use the per-vertex edge flags.
    * We have to observe the edge flag bits set in header->flags which
    * were set during primitive decomposition.  Put those flags into
    * an edge flags array which parallels the vertex array.
    * Later, in the 'unfilled' pipeline stage we'll draw the edge if both
    * the header.flags bit is set AND the per-vertex edgeflag field is set.
    */
   inEdges[0] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_0);
   inEdges[1] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_1);
   inEdges[2] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_2);

   while (clipmask && n >= 3) {
      const unsigned plane_idx = ffs(clipmask)-1;
      const boolean is_user_clip_plane = plane_idx >= 6;
      struct vertex_header *vert_prev = inlist[0];
      boolean *edge_prev = &inEdges[0];
      float dp_prev;
      unsigned outcount = 0;

      dp_prev = getclipdist(clipper, vert_prev, plane_idx);
      clipmask &= ~(1<<plane_idx);

      if (util_is_inf_or_nan(dp_prev))
         return; //discard nan

      assert(n < MAX_CLIPPED_VERTICES);
      if (n >= MAX_CLIPPED_VERTICES)
         return;
      inlist[n] = inlist[0]; /* prevent rotation of vertices */
      inEdges[n] = inEdges[0];

      for (i = 1; i <= n; i++) {
	 struct vertex_header *vert = inlist[i];
         boolean *edge = &inEdges[i];

         float dp = getclipdist(clipper, vert, plane_idx);

         if (util_is_inf_or_nan(dp))
            return; //discard nan

	 if (dp_prev >= 0.0f) {
            assert(outcount < MAX_CLIPPED_VERTICES);
            if (outcount >= MAX_CLIPPED_VERTICES)
               return;
            outEdges[outcount] = *edge_prev;
	    outlist[outcount++] = vert_prev;
	 }

	 if (DIFFERENT_SIGNS(dp, dp_prev)) {
	    struct vertex_header *new_vert;
            boolean *new_edge;

            assert(tmpnr < MAX_CLIPPED_VERTICES + 1);
            if (tmpnr >= MAX_CLIPPED_VERTICES + 1)
               return;
            new_vert = clipper->stage.tmp[tmpnr++];

            assert(outcount < MAX_CLIPPED_VERTICES);
            if (outcount >= MAX_CLIPPED_VERTICES)
               return;

            new_edge = &outEdges[outcount];
	    outlist[outcount++] = new_vert;

	    if (dp < 0.0f) {
	       /* Going out of bounds.  Avoid division by zero as we
		* know dp != dp_prev from DIFFERENT_SIGNS, above.
		*/
	       float t = dp / (dp - dp_prev);
	       interp( clipper, new_vert, t, vert, vert_prev, viewport_index );
	       
	       /* Whether or not to set edge flag for the new vert depends
                * on whether it's a user-defined clipping plane.  We're
                * copying NVIDIA's behaviour here.
		*/
               if (is_user_clip_plane) {
                  /* we want to see an edge along the clip plane */
                  *new_edge = TRUE;
                  new_vert->edgeflag = TRUE;
               }
               else {
                  /* we don't want to see an edge along the frustum clip plane */
                  *new_edge = *edge_prev;
                  new_vert->edgeflag = FALSE;
               }
	    }
            else {
	       /* Coming back in.
		*/
	       float t = dp_prev / (dp_prev - dp);
	       interp( clipper, new_vert, t, vert_prev, vert, viewport_index );

	       /* Copy starting vert's edgeflag:
		*/
	       new_vert->edgeflag = vert_prev->edgeflag;
               *new_edge = *edge_prev;
	    }
	 }

	 vert_prev = vert;
         edge_prev = edge;
	 dp_prev = dp;
      }

      /* swap in/out lists */
      {
	 struct vertex_header **tmp = inlist;
	 inlist = outlist;
	 outlist = tmp;
	 n = outcount;
      }
      {
         boolean *tmp = inEdges;
         inEdges = outEdges;
         outEdges = tmp;
      }

   }

   /* If flat-shading, copy provoking vertex color to polygon vertex[0]
    */
   if (n >= 3) {
      if (clipper->num_flat_attribs) {
         if (stage->draw->rasterizer->flatshade_first) {
            if (inlist[0] != header->v[0]) {
               assert(tmpnr < MAX_CLIPPED_VERTICES + 1);
               if (tmpnr >= MAX_CLIPPED_VERTICES + 1)
                  return;
               inlist[0] = dup_vert(stage, inlist[0], tmpnr++);
               copy_flat(stage, inlist[0], header->v[0]);
            }
         }
         else {
            if (inlist[0] != header->v[2]) {
               assert(tmpnr < MAX_CLIPPED_VERTICES + 1);
               if (tmpnr >= MAX_CLIPPED_VERTICES + 1)
                  return;
               inlist[0] = dup_vert(stage, inlist[0], tmpnr++);
               copy_flat(stage, inlist[0], header->v[2]);
            }
         }
      }
      
      /* Emit the polygon as triangles to the setup stage:
       */
      emit_poly( stage, inlist, inEdges, n, header );
   }
}