/** * Called by vbuf code just before we start buffering primitives. */ void sp_setup_prepare(struct setup_context *setup) { struct softpipe_context *sp = setup->softpipe; if (sp->dirty) { softpipe_update_derived(sp, sp->reduced_api_prim); } /* Note: nr_attrs is only used for debugging (vertex printing) */ setup->nr_vertex_attrs = draw_num_shader_outputs(sp->draw); sp->quad.first->begin( sp->quad.first ); if (sp->reduced_api_prim == PIPE_PRIM_TRIANGLES && sp->rasterizer->fill_front == PIPE_POLYGON_MODE_FILL && sp->rasterizer->fill_back == PIPE_POLYGON_MODE_FILL) { /* we'll do culling */ setup->cull_face = sp->rasterizer->cull_face; } else { /* 'draw' will do culling */ setup->cull_face = PIPE_FACE_NONE; } }
/** * Called by vbuf code just before we start buffering primitives. */ void sp_setup_prepare(struct setup_context *setup) { struct softpipe_context *sp = setup->softpipe; int i; unsigned max_layer = ~0; if (sp->dirty) { softpipe_update_derived(sp, sp->reduced_api_prim); } /* Note: nr_attrs is only used for debugging (vertex printing) */ setup->nr_vertex_attrs = draw_num_shader_outputs(sp->draw); /* * Determine how many layers the fb has (used for clamping layer value). * OpenGL (but not d3d10) permits different amount of layers per rt, however * results are undefined if layer exceeds the amount of layers of ANY * attachment hence don't need separate per cbuf and zsbuf max. */ for (i = 0; i < setup->softpipe->framebuffer.nr_cbufs; i++) { struct pipe_surface *cbuf = setup->softpipe->framebuffer.cbufs[i]; if (cbuf) { max_layer = MIN2(max_layer, cbuf->u.tex.last_layer - cbuf->u.tex.first_layer); } } /* 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->half_pixel_center) { setup->pixel_offset = 0.5f; } else { setup->pixel_offset = 0.0f; } setup->max_layer = max_layer; sp->quad.first->begin( sp->quad.first ); if (sp->reduced_api_prim == PIPE_PRIM_TRIANGLES && sp->rasterizer->fill_front == PIPE_POLYGON_MODE_FILL && sp->rasterizer->fill_back == PIPE_POLYGON_MODE_FILL) { /* we'll do culling */ setup->cull_face = sp->rasterizer->cull_face; } else { /* 'draw' will do culling */ setup->cull_face = PIPE_FACE_NONE; } }
/** * The vertex info describes how to convert the post-transformed vertices * (simple float[][4]) used by the 'draw' module into vertices for * rasterization. * * This function validates the vertex layout and returns a pointer to a * vertex_info object. */ struct vertex_info * softpipe_get_vertex_info(struct softpipe_context *softpipe) { struct vertex_info *vinfo = &softpipe->vertex_info; if (vinfo->num_attribs == 0) { /* compute vertex layout now */ const struct tgsi_shader_info *fsInfo = &softpipe->fs_variant->info; struct vertex_info *vinfo_vbuf = &softpipe->vertex_info_vbuf; const uint num = draw_num_shader_outputs(softpipe->draw); uint i; /* Tell draw_vbuf to simply emit the whole post-xform vertex * as-is. No longer any need to try and emit draw vertex_header * info. */ vinfo_vbuf->num_attribs = 0; for (i = 0; i < num; i++) { draw_emit_vertex_attr(vinfo_vbuf, EMIT_4F, INTERP_PERSPECTIVE, i); } draw_compute_vertex_size(vinfo_vbuf); /* * Loop over fragment shader inputs, searching for the matching output * from the vertex shader. */ vinfo->num_attribs = 0; for (i = 0; i < fsInfo->num_inputs; i++) { int src; enum interp_mode interp = INTERP_LINEAR; switch (fsInfo->input_interpolate[i]) { case TGSI_INTERPOLATE_CONSTANT: interp = INTERP_CONSTANT; break; case TGSI_INTERPOLATE_LINEAR: interp = INTERP_LINEAR; break; case TGSI_INTERPOLATE_PERSPECTIVE: interp = INTERP_PERSPECTIVE; break; case TGSI_INTERPOLATE_COLOR: assert(fsInfo->input_semantic_name[i] == TGSI_SEMANTIC_COLOR); break; default: assert(0); } switch (fsInfo->input_semantic_name[i]) { case TGSI_SEMANTIC_POSITION: interp = INTERP_POS; break; case TGSI_SEMANTIC_COLOR: if (fsInfo->input_interpolate[i] == TGSI_INTERPOLATE_COLOR) { if (softpipe->rasterizer->flatshade) interp = INTERP_CONSTANT; else interp = INTERP_PERSPECTIVE; } break; } /* this includes texcoords and varying vars */ src = draw_find_shader_output(softpipe->draw, fsInfo->input_semantic_name[i], fsInfo->input_semantic_index[i]); if (fsInfo->input_semantic_name[i] == TGSI_SEMANTIC_COLOR && src == 0) /* try and find a bcolor */ src = draw_find_shader_output(softpipe->draw, TGSI_SEMANTIC_BCOLOR, fsInfo->input_semantic_index[i]); draw_emit_vertex_attr(vinfo, EMIT_4F, interp, src); } softpipe->psize_slot = draw_find_shader_output(softpipe->draw, TGSI_SEMANTIC_PSIZE, 0); if (softpipe->psize_slot > 0) { draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_CONSTANT, softpipe->psize_slot); } draw_compute_vertex_size(vinfo); } return vinfo; }
/** * Emit a post-clip polygon to the next pipeline stage. The polygon * will be convex and the provoking vertex will always be vertex[0]. */ static void emit_poly( struct draw_stage *stage, struct vertex_header **inlist, const boolean *edgeflags, unsigned n, const struct prim_header *origPrim) { struct prim_header header; unsigned i; ushort edge_first, edge_middle, edge_last; boolean last_tri_was_null = FALSE; boolean tri_was_not_null = FALSE; if (stage->draw->rasterizer->flatshade_first) { edge_first = DRAW_PIPE_EDGE_FLAG_0; edge_middle = DRAW_PIPE_EDGE_FLAG_1; edge_last = DRAW_PIPE_EDGE_FLAG_2; } else { edge_first = DRAW_PIPE_EDGE_FLAG_2; edge_middle = DRAW_PIPE_EDGE_FLAG_0; edge_last = DRAW_PIPE_EDGE_FLAG_1; } if (!edgeflags[0]) edge_first = 0; /* later stages may need the determinant, but only the sign matters */ header.det = origPrim->det; header.flags = DRAW_PIPE_RESET_STIPPLE | edge_first | edge_middle; header.pad = 0; for (i = 2; i < n; i++, header.flags = edge_middle) { boolean tri_null; /* order the triangle verts to respect the provoking vertex mode */ if (stage->draw->rasterizer->flatshade_first) { header.v[0] = inlist[0]; /* the provoking vertex */ header.v[1] = inlist[i-1]; header.v[2] = inlist[i]; } else { header.v[0] = inlist[i-1]; header.v[1] = inlist[i]; header.v[2] = inlist[0]; /* the provoking vertex */ } tri_null = is_tri_null(stage->draw, &header); /* If we generated a triangle with an area, aka. non-null triangle, * or if the previous triangle was also null then skip all subsequent * null triangles */ if ((tri_was_not_null && tri_null) || (last_tri_was_null && tri_null)) { last_tri_was_null = tri_null; continue; } last_tri_was_null = tri_null; if (!tri_null) { tri_was_not_null = TRUE; } if (!edgeflags[i-1]) { header.flags &= ~edge_middle; } if (i == n - 1 && edgeflags[i]) header.flags |= edge_last; if (DEBUG_CLIP) { uint j, k; debug_printf("Clipped tri: (flat-shade-first = %d)\n", stage->draw->rasterizer->flatshade_first); for (j = 0; j < 3; j++) { debug_printf(" Vert %d: clip: %f %f %f %f\n", j, header.v[j]->clip[0], header.v[j]->clip[1], header.v[j]->clip[2], header.v[j]->clip[3]); for (k = 0; k < draw_num_shader_outputs(stage->draw); k++) { debug_printf(" Vert %d: Attr %d: %f %f %f %f\n", j, k, header.v[j]->data[k][0], header.v[j]->data[k][1], header.v[j]->data[k][2], header.v[j]->data[k][3]); } } } stage->next->tri( stage->next, &header ); } }
/* Interpolate between two vertices to produce a third. */ static void interp( const struct clip_stage *clip, struct vertex_header *dst, float t, const struct vertex_header *out, const struct vertex_header *in, unsigned viewport_index ) { const unsigned nr_attrs = draw_num_shader_outputs(clip->stage.draw); const unsigned pos_attr = draw_current_shader_position_output(clip->stage.draw); const unsigned clip_attr = draw_current_shader_clipvertex_output(clip->stage.draw); unsigned j; float t_nopersp; /* Vertex header. */ dst->clipmask = 0; dst->edgeflag = 0; /* will get overwritten later */ dst->have_clipdist = in->have_clipdist; dst->vertex_id = UNDEFINED_VERTEX_ID; /* Interpolate the clip-space coords. */ interp_attr(dst->clip, t, in->clip, out->clip); /* interpolate the clip-space position */ interp_attr(dst->pre_clip_pos, t, in->pre_clip_pos, out->pre_clip_pos); /* Do the projective divide and viewport transformation to get * new window coordinates: */ { const float *pos = dst->pre_clip_pos; const float *scale = clip->stage.draw->viewports[viewport_index].scale; const float *trans = clip->stage.draw->viewports[viewport_index].translate; const float oow = 1.0f / pos[3]; dst->data[pos_attr][0] = pos[0] * oow * scale[0] + trans[0]; dst->data[pos_attr][1] = pos[1] * oow * scale[1] + trans[1]; dst->data[pos_attr][2] = pos[2] * oow * scale[2] + trans[2]; dst->data[pos_attr][3] = oow; } /** * Compute the t in screen-space instead of 3d space to use * for noperspective interpolation. * * The points can be aligned with the X axis, so in that case try * the Y. When both points are at the same screen position, we can * pick whatever value (the interpolated point won't be in front * anyway), so just use the 3d t. */ { int k; t_nopersp = t; /* find either in.x != out.x or in.y != out.y */ for (k = 0; k < 2; k++) { if (in->clip[k] != out->clip[k]) { /* do divide by W, then compute linear interpolation factor */ float in_coord = in->clip[k] / in->clip[3]; float out_coord = out->clip[k] / out->clip[3]; float dst_coord = dst->clip[k] / dst->clip[3]; t_nopersp = (dst_coord - out_coord) / (in_coord - out_coord); break; } } } /* Other attributes */ for (j = 0; j < nr_attrs; j++) { if (j != pos_attr && j != clip_attr) { if (clip->noperspective_attribs[j]) interp_attr(dst->data[j], t_nopersp, in->data[j], out->data[j]); else interp_attr(dst->data[j], t, in->data[j], out->data[j]); } } }