/* * 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); } }
/*#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; } } } }
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"); } } }
/*#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; }
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; } } } } }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/* 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 ); }
/* 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 ); } }