Path: blob/21.2-virgl/src/gallium/auxiliary/draw/draw_pipe_clip.c
4565 views
/**************************************************************************1*2* Copyright 2007 VMware, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/2627/**28* \brief Clipping stage29*30* \author Keith Whitwell <[email protected]>31*/323334#include "util/u_bitcast.h"35#include "util/u_memory.h"36#include "util/u_math.h"3738#include "pipe/p_shader_tokens.h"3940#include "draw_vs.h"41#include "draw_pipe.h"42#include "draw_fs.h"43#include "draw_gs.h"444546/** Set to 1 to enable printing of coords before/after clipping */47#define DEBUG_CLIP 04849#define MAX_CLIPPED_VERTICES ((2 * (6 + PIPE_MAX_CLIP_PLANES))+1)50515253struct clip_stage {54struct draw_stage stage; /**< base class */5556unsigned pos_attr;57boolean have_clipdist;58int cv_attr;5960/* List of the attributes to be constant interpolated. */61uint num_const_attribs;62uint8_t const_attribs[PIPE_MAX_SHADER_OUTPUTS];63/* List of the attributes to be linear interpolated. */64uint num_linear_attribs;65uint8_t linear_attribs[PIPE_MAX_SHADER_OUTPUTS];66/* List of the attributes to be perspective interpolated. */67uint num_perspect_attribs;68uint8_t perspect_attribs[PIPE_MAX_SHADER_OUTPUTS];6970float (*plane)[4];71};727374/** Cast wrapper */75static inline struct clip_stage *clip_stage(struct draw_stage *stage)76{77return (struct clip_stage *)stage;78}7980static inline unsigned81draw_viewport_index(struct draw_context *draw,82const struct vertex_header *leading_vertex)83{84if (draw_current_shader_uses_viewport_index(draw)) {85unsigned viewport_index_output =86draw_current_shader_viewport_index_output(draw);87unsigned viewport_index =88u_bitcast_f2u(leading_vertex->data[viewport_index_output][0]);89return draw_clamp_viewport_idx(viewport_index);90} else {91return 0;92}93}949596#define LINTERP(T, OUT, IN) ((OUT) + (T) * ((IN) - (OUT)))979899/* All attributes are float[4], so this is easy:100*/101static void interp_attr(float dst[4],102float t,103const float in[4],104const float out[4])105{106dst[0] = LINTERP( t, out[0], in[0] );107dst[1] = LINTERP( t, out[1], in[1] );108dst[2] = LINTERP( t, out[2], in[2] );109dst[3] = LINTERP( t, out[3], in[3] );110}111112113/**114* Copy flat shaded attributes src vertex to dst vertex.115*/116static void copy_flat(struct draw_stage *stage,117struct vertex_header *dst,118const struct vertex_header *src)119{120const struct clip_stage *clipper = clip_stage(stage);121uint i;122for (i = 0; i < clipper->num_const_attribs; i++) {123const uint attr = clipper->const_attribs[i];124COPY_4FV(dst->data[attr], src->data[attr]);125}126}127128/* Interpolate between two vertices to produce a third.129*/130static void interp(const struct clip_stage *clip,131struct vertex_header *dst,132float t,133const struct vertex_header *out,134const struct vertex_header *in,135unsigned viewport_index)136{137const unsigned pos_attr = clip->pos_attr;138unsigned j;139float t_nopersp;140141/* Vertex header.142*/143dst->clipmask = 0;144dst->edgeflag = 0; /* will get overwritten later */145dst->pad = 0;146dst->vertex_id = UNDEFINED_VERTEX_ID;147148/* Interpolate the clip-space coords.149*/150if (clip->cv_attr >= 0) {151interp_attr(dst->data[clip->cv_attr], t,152in->data[clip->cv_attr], out->data[clip->cv_attr]);153}154/* interpolate the clip-space position */155interp_attr(dst->clip_pos, t, in->clip_pos, out->clip_pos);156157/* Do the projective divide and viewport transformation to get158* new window coordinates:159*/160{161const float *pos = dst->clip_pos;162const float *scale =163clip->stage.draw->viewports[viewport_index].scale;164const float *trans =165clip->stage.draw->viewports[viewport_index].translate;166const float oow = 1.0f / pos[3];167168dst->data[pos_attr][0] = pos[0] * oow * scale[0] + trans[0];169dst->data[pos_attr][1] = pos[1] * oow * scale[1] + trans[1];170dst->data[pos_attr][2] = pos[2] * oow * scale[2] + trans[2];171dst->data[pos_attr][3] = oow;172}173174175/* interp perspective attribs */176for (j = 0; j < clip->num_perspect_attribs; j++) {177const unsigned attr = clip->perspect_attribs[j];178interp_attr(dst->data[attr], t, in->data[attr], out->data[attr]);179}180181/**182* Compute the t in screen-space instead of 3d space to use183* for noperspective interpolation.184*185* The points can be aligned with the X axis, so in that case try186* the Y. When both points are at the same screen position, we can187* pick whatever value (the interpolated point won't be in front188* anyway), so just use the 3d t.189*/190if (clip->num_linear_attribs) {191int k;192t_nopersp = t;193/* find either in.x != out.x or in.y != out.y */194for (k = 0; k < 2; k++) {195if (in->clip_pos[k] != out->clip_pos[k]) {196/* do divide by W, then compute linear interpolation factor */197float in_coord = in->clip_pos[k] / in->clip_pos[3];198float out_coord = out->clip_pos[k] / out->clip_pos[3];199float dst_coord = dst->clip_pos[k] / dst->clip_pos[3];200t_nopersp = (dst_coord - out_coord) / (in_coord - out_coord);201break;202}203}204for (j = 0; j < clip->num_linear_attribs; j++) {205const unsigned attr = clip->linear_attribs[j];206interp_attr(dst->data[attr], t_nopersp, in->data[attr], out->data[attr]);207}208}209}210211/**212* Emit a post-clip polygon to the next pipeline stage. The polygon213* will be convex and the provoking vertex will always be vertex[0].214*/215static void emit_poly(struct draw_stage *stage,216struct vertex_header **inlist,217const boolean *edgeflags,218unsigned n,219const struct prim_header *origPrim)220{221const struct clip_stage *clipper = clip_stage(stage);222struct prim_header header;223unsigned i;224ushort edge_first, edge_middle, edge_last;225226if (stage->draw->rasterizer->flatshade_first) {227edge_first = DRAW_PIPE_EDGE_FLAG_0;228edge_middle = DRAW_PIPE_EDGE_FLAG_1;229edge_last = DRAW_PIPE_EDGE_FLAG_2;230}231else {232edge_first = DRAW_PIPE_EDGE_FLAG_2;233edge_middle = DRAW_PIPE_EDGE_FLAG_0;234edge_last = DRAW_PIPE_EDGE_FLAG_1;235}236237if (!edgeflags[0])238edge_first = 0;239240/* later stages may need the determinant, but only the sign matters */241header.det = origPrim->det;242header.flags = DRAW_PIPE_RESET_STIPPLE | edge_first | edge_middle;243header.pad = 0;244245for (i = 2; i < n; i++, header.flags = edge_middle) {246/* order the triangle verts to respect the provoking vertex mode */247if (stage->draw->rasterizer->flatshade_first) {248header.v[0] = inlist[0]; /* the provoking vertex */249header.v[1] = inlist[i-1];250header.v[2] = inlist[i];251}252else {253header.v[0] = inlist[i-1];254header.v[1] = inlist[i];255header.v[2] = inlist[0]; /* the provoking vertex */256}257258if (!edgeflags[i-1]) {259header.flags &= ~edge_middle;260}261262if (i == n - 1 && edgeflags[i])263header.flags |= edge_last;264265if (DEBUG_CLIP) {266uint j, k;267debug_printf("Clipped tri: (flat-shade-first = %d)\n",268stage->draw->rasterizer->flatshade_first);269for (j = 0; j < 3; j++) {270debug_printf(" Vert %d: clip pos: %f %f %f %f\n", j,271header.v[j]->clip_pos[0],272header.v[j]->clip_pos[1],273header.v[j]->clip_pos[2],274header.v[j]->clip_pos[3]);275if (clipper->cv_attr >= 0) {276debug_printf(" Vert %d: cv: %f %f %f %f\n", j,277header.v[j]->data[clipper->cv_attr][0],278header.v[j]->data[clipper->cv_attr][1],279header.v[j]->data[clipper->cv_attr][2],280header.v[j]->data[clipper->cv_attr][3]);281}282for (k = 0; k < draw_num_shader_outputs(stage->draw); k++) {283debug_printf(" Vert %d: Attr %d: %f %f %f %f\n", j, k,284header.v[j]->data[k][0],285header.v[j]->data[k][1],286header.v[j]->data[k][2],287header.v[j]->data[k][3]);288}289}290}291stage->next->tri(stage->next, &header);292}293}294295296static inline float297dot4(const float *a, const float *b)298{299return (a[0] * b[0] +300a[1] * b[1] +301a[2] * b[2] +302a[3] * b[3]);303}304305/*306* this function extracts the clip distance for the current plane,307* it first checks if the shader provided a clip distance, otherwise308* it works out the value using the clipvertex309*/310static inline float getclipdist(const struct clip_stage *clipper,311struct vertex_header *vert,312int plane_idx)313{314const float *plane;315float dp;316if (plane_idx < 6) {317/* ordinary xyz view volume clipping uses pos output */318plane = clipper->plane[plane_idx];319dp = dot4(vert->clip_pos, plane);320}321else if (clipper->have_clipdist) {322/* pick the correct clipdistance element from the output vectors */323int _idx = plane_idx - 6;324int cdi = _idx >= 4;325int vidx = cdi ? _idx - 4 : _idx;326dp = vert->data[draw_current_shader_ccdistance_output(clipper->stage.draw, cdi)][vidx];327} else {328/*329* legacy user clip planes or gl_ClipVertex330*/331plane = clipper->plane[plane_idx];332if (clipper->cv_attr >= 0) {333dp = dot4(vert->data[clipper->cv_attr], plane);334}335else {336dp = dot4(vert->clip_pos, plane);337}338}339return dp;340}341342/* Clip a triangle against the viewport and user clip planes.343*/344static void345do_clip_tri(struct draw_stage *stage,346struct prim_header *header,347unsigned clipmask)348{349struct clip_stage *clipper = clip_stage( stage );350struct vertex_header *a[MAX_CLIPPED_VERTICES];351struct vertex_header *b[MAX_CLIPPED_VERTICES];352struct vertex_header **inlist = a;353struct vertex_header **outlist = b;354struct vertex_header *prov_vertex;355unsigned tmpnr = 0;356unsigned n = 3;357unsigned i;358boolean aEdges[MAX_CLIPPED_VERTICES];359boolean bEdges[MAX_CLIPPED_VERTICES];360boolean *inEdges = aEdges;361boolean *outEdges = bEdges;362int viewport_index = 0;363364inlist[0] = header->v[0];365inlist[1] = header->v[1];366inlist[2] = header->v[2];367368/*369* For d3d10, we need to take this from the leading (first) vertex.370* For GL, we could do anything (as long as we advertize371* GL_UNDEFINED_VERTEX for the VIEWPORT_INDEX_PROVOKING_VERTEX query),372* but it needs to be consistent with what other parts (i.e. driver)373* will do, and that seems easier with GL_PROVOKING_VERTEX logic.374*/375if (stage->draw->rasterizer->flatshade_first) {376prov_vertex = inlist[0];377}378else {379prov_vertex = inlist[2];380}381viewport_index = draw_viewport_index(clipper->stage.draw, prov_vertex);382383if (DEBUG_CLIP) {384const float *v0 = header->v[0]->clip_pos;385const float *v1 = header->v[1]->clip_pos;386const float *v2 = header->v[2]->clip_pos;387debug_printf("Clip triangle pos:\n");388debug_printf(" %f, %f, %f, %f\n", v0[0], v0[1], v0[2], v0[3]);389debug_printf(" %f, %f, %f, %f\n", v1[0], v1[1], v1[2], v1[3]);390debug_printf(" %f, %f, %f, %f\n", v2[0], v2[1], v2[2], v2[3]);391if (clipper->cv_attr >= 0) {392const float *v0 = header->v[0]->data[clipper->cv_attr];393const float *v1 = header->v[1]->data[clipper->cv_attr];394const float *v2 = header->v[2]->data[clipper->cv_attr];395debug_printf("Clip triangle cv:\n");396debug_printf(" %f, %f, %f, %f\n", v0[0], v0[1], v0[2], v0[3]);397debug_printf(" %f, %f, %f, %f\n", v1[0], v1[1], v1[2], v1[3]);398debug_printf(" %f, %f, %f, %f\n", v2[0], v2[1], v2[2], v2[3]);399}400}401402/*403* Note: at this point we can't just use the per-vertex edge flags.404* We have to observe the edge flag bits set in header->flags which405* were set during primitive decomposition. Put those flags into406* an edge flags array which parallels the vertex array.407* Later, in the 'unfilled' pipeline stage we'll draw the edge if both408* the header.flags bit is set AND the per-vertex edgeflag field is set.409*/410inEdges[0] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_0);411inEdges[1] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_1);412inEdges[2] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_2);413414while (clipmask && n >= 3) {415const unsigned plane_idx = ffs(clipmask)-1;416const boolean is_user_clip_plane = plane_idx >= 6;417struct vertex_header *vert_prev = inlist[0];418boolean *edge_prev = &inEdges[0];419float dp_prev;420unsigned outcount = 0;421422dp_prev = getclipdist(clipper, vert_prev, plane_idx);423clipmask &= ~(1<<plane_idx);424425if (util_is_inf_or_nan(dp_prev))426return; //discard nan427428assert(n < MAX_CLIPPED_VERTICES);429if (n >= MAX_CLIPPED_VERTICES)430return;431inlist[n] = inlist[0]; /* prevent rotation of vertices */432inEdges[n] = inEdges[0];433434for (i = 1; i <= n; i++) {435struct vertex_header *vert = inlist[i];436boolean *edge = &inEdges[i];437boolean different_sign;438439float dp = getclipdist(clipper, vert, plane_idx);440441if (util_is_inf_or_nan(dp))442return; //discard nan443444if (dp_prev >= 0.0f) {445assert(outcount < MAX_CLIPPED_VERTICES);446if (outcount >= MAX_CLIPPED_VERTICES)447return;448outEdges[outcount] = *edge_prev;449outlist[outcount++] = vert_prev;450different_sign = dp < 0.0f;451} else {452different_sign = !(dp < 0.0f);453}454455if (different_sign) {456struct vertex_header *new_vert;457boolean *new_edge;458459assert(tmpnr < MAX_CLIPPED_VERTICES + 1);460if (tmpnr >= MAX_CLIPPED_VERTICES + 1)461return;462new_vert = clipper->stage.tmp[tmpnr++];463464assert(outcount < MAX_CLIPPED_VERTICES);465if (outcount >= MAX_CLIPPED_VERTICES)466return;467468new_edge = &outEdges[outcount];469outlist[outcount++] = new_vert;470471if (dp < 0.0f) {472/* Going out of bounds. Avoid division by zero as we473* know dp != dp_prev from different_sign, above.474*/475float t = dp / (dp - dp_prev);476interp( clipper, new_vert, t, vert, vert_prev, viewport_index );477478/* Whether or not to set edge flag for the new vert depends479* on whether it's a user-defined clipping plane. We're480* copying NVIDIA's behaviour here.481*/482if (is_user_clip_plane) {483/* we want to see an edge along the clip plane */484*new_edge = TRUE;485new_vert->edgeflag = TRUE;486}487else {488/* we don't want to see an edge along the frustum clip plane */489*new_edge = *edge_prev;490new_vert->edgeflag = FALSE;491}492}493else {494/* Coming back in.495*/496float t = dp_prev / (dp_prev - dp);497interp( clipper, new_vert, t, vert_prev, vert, viewport_index );498499/* Copy starting vert's edgeflag:500*/501new_vert->edgeflag = vert_prev->edgeflag;502*new_edge = *edge_prev;503}504}505506vert_prev = vert;507edge_prev = edge;508dp_prev = dp;509}510511/* swap in/out lists */512{513struct vertex_header **tmp = inlist;514inlist = outlist;515outlist = tmp;516n = outcount;517}518{519boolean *tmp = inEdges;520inEdges = outEdges;521outEdges = tmp;522}523524}525526/* If constant interpolated, copy provoking vertex attrib to polygon vertex[0]527*/528if (n >= 3) {529if (clipper->num_const_attribs) {530if (stage->draw->rasterizer->flatshade_first) {531if (inlist[0] != header->v[0]) {532assert(tmpnr < MAX_CLIPPED_VERTICES + 1);533if (tmpnr >= MAX_CLIPPED_VERTICES + 1)534return;535inlist[0] = dup_vert(stage, inlist[0], tmpnr++);536copy_flat(stage, inlist[0], header->v[0]);537}538}539else {540if (inlist[0] != header->v[2]) {541assert(tmpnr < MAX_CLIPPED_VERTICES + 1);542if (tmpnr >= MAX_CLIPPED_VERTICES + 1)543return;544inlist[0] = dup_vert(stage, inlist[0], tmpnr++);545copy_flat(stage, inlist[0], header->v[2]);546}547}548}549550/* Emit the polygon as triangles to the setup stage:551*/552emit_poly(stage, inlist, inEdges, n, header);553}554}555556557/* Clip a line against the viewport and user clip planes.558*/559static void560do_clip_line(struct draw_stage *stage,561struct prim_header *header,562unsigned clipmask)563{564const struct clip_stage *clipper = clip_stage(stage);565struct vertex_header *v0 = header->v[0];566struct vertex_header *v1 = header->v[1];567struct vertex_header *prov_vertex;568float t0 = 0.0F;569float t1 = 0.0F;570struct prim_header newprim;571int viewport_index;572573newprim.flags = header->flags;574575if (stage->draw->rasterizer->flatshade_first) {576prov_vertex = v0;577}578else {579prov_vertex = v1;580}581viewport_index = draw_viewport_index(clipper->stage.draw, prov_vertex);582583while (clipmask) {584const unsigned plane_idx = ffs(clipmask)-1;585const float dp0 = getclipdist(clipper, v0, plane_idx);586const float dp1 = getclipdist(clipper, v1, plane_idx);587588if (util_is_inf_or_nan(dp0) || util_is_inf_or_nan(dp1))589return; //discard nan590591if (dp1 < 0.0F) {592float t = dp1 / (dp1 - dp0);593t1 = MAX2(t1, t);594}595596if (dp0 < 0.0F) {597float t = dp0 / (dp0 - dp1);598t0 = MAX2(t0, t);599}600601if (t0 + t1 >= 1.0F)602return; /* discard */603604clipmask &= ~(1 << plane_idx); /* turn off this plane's bit */605}606607if (v0->clipmask) {608interp( clipper, stage->tmp[0], t0, v0, v1, viewport_index );609if (stage->draw->rasterizer->flatshade_first) {610copy_flat(stage, stage->tmp[0], v0); /* copy v0 color to tmp[0] */611}612else {613copy_flat(stage, stage->tmp[0], v1); /* copy v1 color to tmp[0] */614}615newprim.v[0] = stage->tmp[0];616}617else {618newprim.v[0] = v0;619}620621if (v1->clipmask) {622interp( clipper, stage->tmp[1], t1, v1, v0, viewport_index );623if (stage->draw->rasterizer->flatshade_first) {624copy_flat(stage, stage->tmp[1], v0); /* copy v0 color to tmp[1] */625}626else {627copy_flat(stage, stage->tmp[1], v1); /* copy v1 color to tmp[1] */628}629newprim.v[1] = stage->tmp[1];630}631else {632newprim.v[1] = v1;633}634635stage->next->line( stage->next, &newprim );636}637638639static void640clip_point(struct draw_stage *stage, struct prim_header *header)641{642if (header->v[0]->clipmask == 0)643stage->next->point( stage->next, header );644}645646647/*648* Clip points but ignore the first 4 (xy) clip planes.649* (Because the generated clip mask is completely unaffacted by guard band,650* we still need to manually evaluate the x/y planes if they are outside651* the guard band and not just outside the vp.)652*/653static void654clip_point_guard_xy(struct draw_stage *stage, struct prim_header *header)655{656unsigned clipmask = header->v[0]->clipmask;657if ((clipmask & 0xffffffff) == 0)658stage->next->point(stage->next, header);659else if ((clipmask & 0xfffffff0) == 0) {660while (clipmask) {661const unsigned plane_idx = ffs(clipmask)-1;662clipmask &= ~(1 << plane_idx); /* turn off this plane's bit */663/* TODO: this should really do proper guardband clipping,664* currently just throw out infs/nans.665* Also note that vertices with negative w values MUST be tossed666* out (not sure if proper guardband clipping would do this667* automatically). These would usually be captured by depth clip668* too but this can be disabled.669*/670if (header->v[0]->clip_pos[3] <= 0.0f ||671util_is_inf_or_nan(header->v[0]->clip_pos[0]) ||672util_is_inf_or_nan(header->v[0]->clip_pos[1]))673return;674}675stage->next->point(stage->next, header);676}677}678679680static void681clip_first_point(struct draw_stage *stage, struct prim_header *header)682{683stage->point = stage->draw->guard_band_points_xy ? clip_point_guard_xy : clip_point;684stage->point(stage, header);685}686687688static void689clip_line(struct draw_stage *stage, struct prim_header *header)690{691unsigned clipmask = (header->v[0]->clipmask |692header->v[1]->clipmask);693694if (clipmask == 0) {695/* no clipping needed */696stage->next->line( stage->next, header );697}698else if ((header->v[0]->clipmask &699header->v[1]->clipmask) == 0) {700do_clip_line(stage, header, clipmask);701}702/* else, totally clipped */703}704705706static void707clip_tri(struct draw_stage *stage, struct prim_header *header)708{709unsigned clipmask = (header->v[0]->clipmask |710header->v[1]->clipmask |711header->v[2]->clipmask);712713if (clipmask == 0) {714/* no clipping needed */715stage->next->tri( stage->next, header );716}717else if ((header->v[0]->clipmask &718header->v[1]->clipmask &719header->v[2]->clipmask) == 0) {720do_clip_tri(stage, header, clipmask);721}722}723724725static int726find_interp(const struct draw_fragment_shader *fs, int *indexed_interp,727uint semantic_name, uint semantic_index)728{729int interp;730/* If it's gl_{Front,Back}{,Secondary}Color, pick up the mode731* from the array we've filled before. */732if ((semantic_name == TGSI_SEMANTIC_COLOR ||733semantic_name == TGSI_SEMANTIC_BCOLOR) &&734semantic_index < 2) {735interp = indexed_interp[semantic_index];736} else if (semantic_name == TGSI_SEMANTIC_POSITION ||737semantic_name == TGSI_SEMANTIC_CLIPVERTEX) {738/* these inputs are handled specially always */739return -1;740} else {741/* Otherwise, search in the FS inputs, with a decent default742* if we don't find it.743* This probably only matters for layer, vpindex, culldist, maybe744* front_face.745*/746uint j;747if (semantic_name == TGSI_SEMANTIC_LAYER ||748semantic_name == TGSI_SEMANTIC_VIEWPORT_INDEX) {749interp = TGSI_INTERPOLATE_CONSTANT;750}751else {752interp = TGSI_INTERPOLATE_PERSPECTIVE;753}754if (fs) {755for (j = 0; j < fs->info.num_inputs; j++) {756if (semantic_name == fs->info.input_semantic_name[j] &&757semantic_index == fs->info.input_semantic_index[j]) {758interp = fs->info.input_interpolate[j];759break;760}761}762}763}764return interp;765}766767/* Update state. Could further delay this until we hit the first768* primitive that really requires clipping.769*/770static void771clip_init_state(struct draw_stage *stage)772{773struct clip_stage *clipper = clip_stage(stage);774const struct draw_context *draw = stage->draw;775const struct draw_fragment_shader *fs = draw->fs.fragment_shader;776const struct tgsi_shader_info *info = draw_get_shader_info(draw);777uint i, j;778int indexed_interp[2];779780clipper->pos_attr = draw_current_shader_position_output(draw);781clipper->have_clipdist = draw_current_shader_num_written_clipdistances(draw) > 0;782if (draw_current_shader_clipvertex_output(draw) != clipper->pos_attr) {783clipper->cv_attr = (int)draw_current_shader_clipvertex_output(draw);784}785else {786clipper->cv_attr = -1;787}788789/* We need to know for each attribute what kind of interpolation is790* done on it (flat, smooth or noperspective). But the information791* is not directly accessible for outputs, only for inputs. So we792* have to match semantic name and index between the VS (or GS/ES)793* outputs and the FS inputs to get to the interpolation mode.794*795* The only hitch is with gl_FrontColor/gl_BackColor which map to796* gl_Color, and their Secondary versions. First there are (up to)797* two outputs for one input, so we tuck the information in a798* specific array. Second if they don't have qualifiers, the799* default value has to be picked from the global shade mode.800*801* Of course, if we don't have a fragment shader in the first802* place, defaults should be used.803*/804805/* First pick up the interpolation mode for806* gl_Color/gl_SecondaryColor, with the correct default.807*/808indexed_interp[0] = indexed_interp[1] = draw->rasterizer->flatshade ?809TGSI_INTERPOLATE_CONSTANT : TGSI_INTERPOLATE_PERSPECTIVE;810811if (fs) {812for (i = 0; i < fs->info.num_inputs; i++) {813if (fs->info.input_semantic_name[i] == TGSI_SEMANTIC_COLOR &&814fs->info.input_semantic_index[i] < 2) {815if (fs->info.input_interpolate[i] != TGSI_INTERPOLATE_COLOR)816indexed_interp[fs->info.input_semantic_index[i]] = fs->info.input_interpolate[i];817}818}819}820821/* Then resolve the interpolation mode for every output attribute. */822823clipper->num_const_attribs = 0;824clipper->num_linear_attribs = 0;825clipper->num_perspect_attribs = 0;826for (i = 0; i < info->num_outputs; i++) {827/* Find the interpolation mode for a specific attribute */828int interp = find_interp(fs, indexed_interp,829info->output_semantic_name[i],830info->output_semantic_index[i]);831switch (interp) {832case TGSI_INTERPOLATE_CONSTANT:833clipper->const_attribs[clipper->num_const_attribs] = i;834clipper->num_const_attribs++;835break;836case TGSI_INTERPOLATE_LINEAR:837clipper->linear_attribs[clipper->num_linear_attribs] = i;838clipper->num_linear_attribs++;839break;840case TGSI_INTERPOLATE_PERSPECTIVE:841clipper->perspect_attribs[clipper->num_perspect_attribs] = i;842clipper->num_perspect_attribs++;843break;844case TGSI_INTERPOLATE_COLOR:845if (draw->rasterizer->flatshade) {846clipper->const_attribs[clipper->num_const_attribs] = i;847clipper->num_const_attribs++;848} else {849clipper->perspect_attribs[clipper->num_perspect_attribs] = i;850clipper->num_perspect_attribs++;851}852break;853default:854assert(interp == -1);855break;856}857}858/* Search the extra vertex attributes */859for (j = 0; j < draw->extra_shader_outputs.num; j++) {860/* Find the interpolation mode for a specific attribute */861int interp = find_interp(fs, indexed_interp,862draw->extra_shader_outputs.semantic_name[j],863draw->extra_shader_outputs.semantic_index[j]);864switch (interp) {865case TGSI_INTERPOLATE_CONSTANT:866clipper->const_attribs[clipper->num_const_attribs] = i + j;867clipper->num_const_attribs++;868break;869case TGSI_INTERPOLATE_LINEAR:870clipper->linear_attribs[clipper->num_linear_attribs] = i + j;871clipper->num_linear_attribs++;872break;873case TGSI_INTERPOLATE_PERSPECTIVE:874clipper->perspect_attribs[clipper->num_perspect_attribs] = i + j;875clipper->num_perspect_attribs++;876break;877default:878assert(interp == -1);879break;880}881}882883stage->tri = clip_tri;884stage->line = clip_line;885}886887888889static void clip_first_tri(struct draw_stage *stage,890struct prim_header *header)891{892clip_init_state( stage );893stage->tri( stage, header );894}895896static void clip_first_line(struct draw_stage *stage,897struct prim_header *header)898{899clip_init_state( stage );900stage->line( stage, header );901}902903904static void clip_flush(struct draw_stage *stage, unsigned flags)905{906stage->tri = clip_first_tri;907stage->line = clip_first_line;908stage->next->flush( stage->next, flags );909}910911912static void clip_reset_stipple_counter(struct draw_stage *stage)913{914stage->next->reset_stipple_counter( stage->next );915}916917918static void clip_destroy(struct draw_stage *stage)919{920draw_free_temp_verts( stage );921FREE( stage );922}923924925/**926* Allocate a new clipper stage.927* \return pointer to new stage object928*/929struct draw_stage *draw_clip_stage(struct draw_context *draw)930{931struct clip_stage *clipper = CALLOC_STRUCT(clip_stage);932if (!clipper)933goto fail;934935clipper->stage.draw = draw;936clipper->stage.name = "clipper";937clipper->stage.point = clip_first_point;938clipper->stage.line = clip_first_line;939clipper->stage.tri = clip_first_tri;940clipper->stage.flush = clip_flush;941clipper->stage.reset_stipple_counter = clip_reset_stipple_counter;942clipper->stage.destroy = clip_destroy;943944clipper->plane = draw->plane;945946if (!draw_alloc_temp_verts( &clipper->stage, MAX_CLIPPED_VERTICES+1 ))947goto fail;948949return &clipper->stage;950951fail:952if (clipper)953clipper->stage.destroy( &clipper->stage );954955return NULL;956}957958959