Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/auxiliary/draw/draw_pipe_clip.c
4565 views
1
/**************************************************************************
2
*
3
* Copyright 2007 VMware, Inc.
4
* 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
8
* "Software"), to deal in the Software without restriction, including
9
* without limitation the rights to use, copy, modify, merge, publish,
10
* distribute, sub license, and/or sell copies of the Software, and to
11
* permit persons to whom the Software is furnished to do so, subject to
12
* the following conditions:
13
*
14
* The above copyright notice and this permission notice (including the
15
* next paragraph) shall be included in all copies or substantial portions
16
* of the Software.
17
*
18
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
*
26
**************************************************************************/
27
28
/**
29
* \brief Clipping stage
30
*
31
* \author Keith Whitwell <[email protected]>
32
*/
33
34
35
#include "util/u_bitcast.h"
36
#include "util/u_memory.h"
37
#include "util/u_math.h"
38
39
#include "pipe/p_shader_tokens.h"
40
41
#include "draw_vs.h"
42
#include "draw_pipe.h"
43
#include "draw_fs.h"
44
#include "draw_gs.h"
45
46
47
/** Set to 1 to enable printing of coords before/after clipping */
48
#define DEBUG_CLIP 0
49
50
#define MAX_CLIPPED_VERTICES ((2 * (6 + PIPE_MAX_CLIP_PLANES))+1)
51
52
53
54
struct clip_stage {
55
struct draw_stage stage; /**< base class */
56
57
unsigned pos_attr;
58
boolean have_clipdist;
59
int cv_attr;
60
61
/* List of the attributes to be constant interpolated. */
62
uint num_const_attribs;
63
uint8_t const_attribs[PIPE_MAX_SHADER_OUTPUTS];
64
/* List of the attributes to be linear interpolated. */
65
uint num_linear_attribs;
66
uint8_t linear_attribs[PIPE_MAX_SHADER_OUTPUTS];
67
/* List of the attributes to be perspective interpolated. */
68
uint num_perspect_attribs;
69
uint8_t perspect_attribs[PIPE_MAX_SHADER_OUTPUTS];
70
71
float (*plane)[4];
72
};
73
74
75
/** Cast wrapper */
76
static inline struct clip_stage *clip_stage(struct draw_stage *stage)
77
{
78
return (struct clip_stage *)stage;
79
}
80
81
static inline unsigned
82
draw_viewport_index(struct draw_context *draw,
83
const struct vertex_header *leading_vertex)
84
{
85
if (draw_current_shader_uses_viewport_index(draw)) {
86
unsigned viewport_index_output =
87
draw_current_shader_viewport_index_output(draw);
88
unsigned viewport_index =
89
u_bitcast_f2u(leading_vertex->data[viewport_index_output][0]);
90
return draw_clamp_viewport_idx(viewport_index);
91
} else {
92
return 0;
93
}
94
}
95
96
97
#define LINTERP(T, OUT, IN) ((OUT) + (T) * ((IN) - (OUT)))
98
99
100
/* All attributes are float[4], so this is easy:
101
*/
102
static void interp_attr(float dst[4],
103
float t,
104
const float in[4],
105
const float out[4])
106
{
107
dst[0] = LINTERP( t, out[0], in[0] );
108
dst[1] = LINTERP( t, out[1], in[1] );
109
dst[2] = LINTERP( t, out[2], in[2] );
110
dst[3] = LINTERP( t, out[3], in[3] );
111
}
112
113
114
/**
115
* Copy flat shaded attributes src vertex to dst vertex.
116
*/
117
static void copy_flat(struct draw_stage *stage,
118
struct vertex_header *dst,
119
const struct vertex_header *src)
120
{
121
const struct clip_stage *clipper = clip_stage(stage);
122
uint i;
123
for (i = 0; i < clipper->num_const_attribs; i++) {
124
const uint attr = clipper->const_attribs[i];
125
COPY_4FV(dst->data[attr], src->data[attr]);
126
}
127
}
128
129
/* Interpolate between two vertices to produce a third.
130
*/
131
static void interp(const struct clip_stage *clip,
132
struct vertex_header *dst,
133
float t,
134
const struct vertex_header *out,
135
const struct vertex_header *in,
136
unsigned viewport_index)
137
{
138
const unsigned pos_attr = clip->pos_attr;
139
unsigned j;
140
float t_nopersp;
141
142
/* Vertex header.
143
*/
144
dst->clipmask = 0;
145
dst->edgeflag = 0; /* will get overwritten later */
146
dst->pad = 0;
147
dst->vertex_id = UNDEFINED_VERTEX_ID;
148
149
/* Interpolate the clip-space coords.
150
*/
151
if (clip->cv_attr >= 0) {
152
interp_attr(dst->data[clip->cv_attr], t,
153
in->data[clip->cv_attr], out->data[clip->cv_attr]);
154
}
155
/* interpolate the clip-space position */
156
interp_attr(dst->clip_pos, t, in->clip_pos, out->clip_pos);
157
158
/* Do the projective divide and viewport transformation to get
159
* new window coordinates:
160
*/
161
{
162
const float *pos = dst->clip_pos;
163
const float *scale =
164
clip->stage.draw->viewports[viewport_index].scale;
165
const float *trans =
166
clip->stage.draw->viewports[viewport_index].translate;
167
const float oow = 1.0f / pos[3];
168
169
dst->data[pos_attr][0] = pos[0] * oow * scale[0] + trans[0];
170
dst->data[pos_attr][1] = pos[1] * oow * scale[1] + trans[1];
171
dst->data[pos_attr][2] = pos[2] * oow * scale[2] + trans[2];
172
dst->data[pos_attr][3] = oow;
173
}
174
175
176
/* interp perspective attribs */
177
for (j = 0; j < clip->num_perspect_attribs; j++) {
178
const unsigned attr = clip->perspect_attribs[j];
179
interp_attr(dst->data[attr], t, in->data[attr], out->data[attr]);
180
}
181
182
/**
183
* Compute the t in screen-space instead of 3d space to use
184
* for noperspective interpolation.
185
*
186
* The points can be aligned with the X axis, so in that case try
187
* the Y. When both points are at the same screen position, we can
188
* pick whatever value (the interpolated point won't be in front
189
* anyway), so just use the 3d t.
190
*/
191
if (clip->num_linear_attribs) {
192
int k;
193
t_nopersp = t;
194
/* find either in.x != out.x or in.y != out.y */
195
for (k = 0; k < 2; k++) {
196
if (in->clip_pos[k] != out->clip_pos[k]) {
197
/* do divide by W, then compute linear interpolation factor */
198
float in_coord = in->clip_pos[k] / in->clip_pos[3];
199
float out_coord = out->clip_pos[k] / out->clip_pos[3];
200
float dst_coord = dst->clip_pos[k] / dst->clip_pos[3];
201
t_nopersp = (dst_coord - out_coord) / (in_coord - out_coord);
202
break;
203
}
204
}
205
for (j = 0; j < clip->num_linear_attribs; j++) {
206
const unsigned attr = clip->linear_attribs[j];
207
interp_attr(dst->data[attr], t_nopersp, in->data[attr], out->data[attr]);
208
}
209
}
210
}
211
212
/**
213
* Emit a post-clip polygon to the next pipeline stage. The polygon
214
* will be convex and the provoking vertex will always be vertex[0].
215
*/
216
static void emit_poly(struct draw_stage *stage,
217
struct vertex_header **inlist,
218
const boolean *edgeflags,
219
unsigned n,
220
const struct prim_header *origPrim)
221
{
222
const struct clip_stage *clipper = clip_stage(stage);
223
struct prim_header header;
224
unsigned i;
225
ushort edge_first, edge_middle, edge_last;
226
227
if (stage->draw->rasterizer->flatshade_first) {
228
edge_first = DRAW_PIPE_EDGE_FLAG_0;
229
edge_middle = DRAW_PIPE_EDGE_FLAG_1;
230
edge_last = DRAW_PIPE_EDGE_FLAG_2;
231
}
232
else {
233
edge_first = DRAW_PIPE_EDGE_FLAG_2;
234
edge_middle = DRAW_PIPE_EDGE_FLAG_0;
235
edge_last = DRAW_PIPE_EDGE_FLAG_1;
236
}
237
238
if (!edgeflags[0])
239
edge_first = 0;
240
241
/* later stages may need the determinant, but only the sign matters */
242
header.det = origPrim->det;
243
header.flags = DRAW_PIPE_RESET_STIPPLE | edge_first | edge_middle;
244
header.pad = 0;
245
246
for (i = 2; i < n; i++, header.flags = edge_middle) {
247
/* order the triangle verts to respect the provoking vertex mode */
248
if (stage->draw->rasterizer->flatshade_first) {
249
header.v[0] = inlist[0]; /* the provoking vertex */
250
header.v[1] = inlist[i-1];
251
header.v[2] = inlist[i];
252
}
253
else {
254
header.v[0] = inlist[i-1];
255
header.v[1] = inlist[i];
256
header.v[2] = inlist[0]; /* the provoking vertex */
257
}
258
259
if (!edgeflags[i-1]) {
260
header.flags &= ~edge_middle;
261
}
262
263
if (i == n - 1 && edgeflags[i])
264
header.flags |= edge_last;
265
266
if (DEBUG_CLIP) {
267
uint j, k;
268
debug_printf("Clipped tri: (flat-shade-first = %d)\n",
269
stage->draw->rasterizer->flatshade_first);
270
for (j = 0; j < 3; j++) {
271
debug_printf(" Vert %d: clip pos: %f %f %f %f\n", j,
272
header.v[j]->clip_pos[0],
273
header.v[j]->clip_pos[1],
274
header.v[j]->clip_pos[2],
275
header.v[j]->clip_pos[3]);
276
if (clipper->cv_attr >= 0) {
277
debug_printf(" Vert %d: cv: %f %f %f %f\n", j,
278
header.v[j]->data[clipper->cv_attr][0],
279
header.v[j]->data[clipper->cv_attr][1],
280
header.v[j]->data[clipper->cv_attr][2],
281
header.v[j]->data[clipper->cv_attr][3]);
282
}
283
for (k = 0; k < draw_num_shader_outputs(stage->draw); k++) {
284
debug_printf(" Vert %d: Attr %d: %f %f %f %f\n", j, k,
285
header.v[j]->data[k][0],
286
header.v[j]->data[k][1],
287
header.v[j]->data[k][2],
288
header.v[j]->data[k][3]);
289
}
290
}
291
}
292
stage->next->tri(stage->next, &header);
293
}
294
}
295
296
297
static inline float
298
dot4(const float *a, const float *b)
299
{
300
return (a[0] * b[0] +
301
a[1] * b[1] +
302
a[2] * b[2] +
303
a[3] * b[3]);
304
}
305
306
/*
307
* this function extracts the clip distance for the current plane,
308
* it first checks if the shader provided a clip distance, otherwise
309
* it works out the value using the clipvertex
310
*/
311
static inline float getclipdist(const struct clip_stage *clipper,
312
struct vertex_header *vert,
313
int plane_idx)
314
{
315
const float *plane;
316
float dp;
317
if (plane_idx < 6) {
318
/* ordinary xyz view volume clipping uses pos output */
319
plane = clipper->plane[plane_idx];
320
dp = dot4(vert->clip_pos, plane);
321
}
322
else if (clipper->have_clipdist) {
323
/* pick the correct clipdistance element from the output vectors */
324
int _idx = plane_idx - 6;
325
int cdi = _idx >= 4;
326
int vidx = cdi ? _idx - 4 : _idx;
327
dp = vert->data[draw_current_shader_ccdistance_output(clipper->stage.draw, cdi)][vidx];
328
} else {
329
/*
330
* legacy user clip planes or gl_ClipVertex
331
*/
332
plane = clipper->plane[plane_idx];
333
if (clipper->cv_attr >= 0) {
334
dp = dot4(vert->data[clipper->cv_attr], plane);
335
}
336
else {
337
dp = dot4(vert->clip_pos, plane);
338
}
339
}
340
return dp;
341
}
342
343
/* Clip a triangle against the viewport and user clip planes.
344
*/
345
static void
346
do_clip_tri(struct draw_stage *stage,
347
struct prim_header *header,
348
unsigned clipmask)
349
{
350
struct clip_stage *clipper = clip_stage( stage );
351
struct vertex_header *a[MAX_CLIPPED_VERTICES];
352
struct vertex_header *b[MAX_CLIPPED_VERTICES];
353
struct vertex_header **inlist = a;
354
struct vertex_header **outlist = b;
355
struct vertex_header *prov_vertex;
356
unsigned tmpnr = 0;
357
unsigned n = 3;
358
unsigned i;
359
boolean aEdges[MAX_CLIPPED_VERTICES];
360
boolean bEdges[MAX_CLIPPED_VERTICES];
361
boolean *inEdges = aEdges;
362
boolean *outEdges = bEdges;
363
int viewport_index = 0;
364
365
inlist[0] = header->v[0];
366
inlist[1] = header->v[1];
367
inlist[2] = header->v[2];
368
369
/*
370
* For d3d10, we need to take this from the leading (first) vertex.
371
* For GL, we could do anything (as long as we advertize
372
* GL_UNDEFINED_VERTEX for the VIEWPORT_INDEX_PROVOKING_VERTEX query),
373
* but it needs to be consistent with what other parts (i.e. driver)
374
* will do, and that seems easier with GL_PROVOKING_VERTEX logic.
375
*/
376
if (stage->draw->rasterizer->flatshade_first) {
377
prov_vertex = inlist[0];
378
}
379
else {
380
prov_vertex = inlist[2];
381
}
382
viewport_index = draw_viewport_index(clipper->stage.draw, prov_vertex);
383
384
if (DEBUG_CLIP) {
385
const float *v0 = header->v[0]->clip_pos;
386
const float *v1 = header->v[1]->clip_pos;
387
const float *v2 = header->v[2]->clip_pos;
388
debug_printf("Clip triangle pos:\n");
389
debug_printf(" %f, %f, %f, %f\n", v0[0], v0[1], v0[2], v0[3]);
390
debug_printf(" %f, %f, %f, %f\n", v1[0], v1[1], v1[2], v1[3]);
391
debug_printf(" %f, %f, %f, %f\n", v2[0], v2[1], v2[2], v2[3]);
392
if (clipper->cv_attr >= 0) {
393
const float *v0 = header->v[0]->data[clipper->cv_attr];
394
const float *v1 = header->v[1]->data[clipper->cv_attr];
395
const float *v2 = header->v[2]->data[clipper->cv_attr];
396
debug_printf("Clip triangle cv:\n");
397
debug_printf(" %f, %f, %f, %f\n", v0[0], v0[1], v0[2], v0[3]);
398
debug_printf(" %f, %f, %f, %f\n", v1[0], v1[1], v1[2], v1[3]);
399
debug_printf(" %f, %f, %f, %f\n", v2[0], v2[1], v2[2], v2[3]);
400
}
401
}
402
403
/*
404
* Note: at this point we can't just use the per-vertex edge flags.
405
* We have to observe the edge flag bits set in header->flags which
406
* were set during primitive decomposition. Put those flags into
407
* an edge flags array which parallels the vertex array.
408
* Later, in the 'unfilled' pipeline stage we'll draw the edge if both
409
* the header.flags bit is set AND the per-vertex edgeflag field is set.
410
*/
411
inEdges[0] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_0);
412
inEdges[1] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_1);
413
inEdges[2] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_2);
414
415
while (clipmask && n >= 3) {
416
const unsigned plane_idx = ffs(clipmask)-1;
417
const boolean is_user_clip_plane = plane_idx >= 6;
418
struct vertex_header *vert_prev = inlist[0];
419
boolean *edge_prev = &inEdges[0];
420
float dp_prev;
421
unsigned outcount = 0;
422
423
dp_prev = getclipdist(clipper, vert_prev, plane_idx);
424
clipmask &= ~(1<<plane_idx);
425
426
if (util_is_inf_or_nan(dp_prev))
427
return; //discard nan
428
429
assert(n < MAX_CLIPPED_VERTICES);
430
if (n >= MAX_CLIPPED_VERTICES)
431
return;
432
inlist[n] = inlist[0]; /* prevent rotation of vertices */
433
inEdges[n] = inEdges[0];
434
435
for (i = 1; i <= n; i++) {
436
struct vertex_header *vert = inlist[i];
437
boolean *edge = &inEdges[i];
438
boolean different_sign;
439
440
float dp = getclipdist(clipper, vert, plane_idx);
441
442
if (util_is_inf_or_nan(dp))
443
return; //discard nan
444
445
if (dp_prev >= 0.0f) {
446
assert(outcount < MAX_CLIPPED_VERTICES);
447
if (outcount >= MAX_CLIPPED_VERTICES)
448
return;
449
outEdges[outcount] = *edge_prev;
450
outlist[outcount++] = vert_prev;
451
different_sign = dp < 0.0f;
452
} else {
453
different_sign = !(dp < 0.0f);
454
}
455
456
if (different_sign) {
457
struct vertex_header *new_vert;
458
boolean *new_edge;
459
460
assert(tmpnr < MAX_CLIPPED_VERTICES + 1);
461
if (tmpnr >= MAX_CLIPPED_VERTICES + 1)
462
return;
463
new_vert = clipper->stage.tmp[tmpnr++];
464
465
assert(outcount < MAX_CLIPPED_VERTICES);
466
if (outcount >= MAX_CLIPPED_VERTICES)
467
return;
468
469
new_edge = &outEdges[outcount];
470
outlist[outcount++] = new_vert;
471
472
if (dp < 0.0f) {
473
/* Going out of bounds. Avoid division by zero as we
474
* know dp != dp_prev from different_sign, above.
475
*/
476
float t = dp / (dp - dp_prev);
477
interp( clipper, new_vert, t, vert, vert_prev, viewport_index );
478
479
/* Whether or not to set edge flag for the new vert depends
480
* on whether it's a user-defined clipping plane. We're
481
* copying NVIDIA's behaviour here.
482
*/
483
if (is_user_clip_plane) {
484
/* we want to see an edge along the clip plane */
485
*new_edge = TRUE;
486
new_vert->edgeflag = TRUE;
487
}
488
else {
489
/* we don't want to see an edge along the frustum clip plane */
490
*new_edge = *edge_prev;
491
new_vert->edgeflag = FALSE;
492
}
493
}
494
else {
495
/* Coming back in.
496
*/
497
float t = dp_prev / (dp_prev - dp);
498
interp( clipper, new_vert, t, vert_prev, vert, viewport_index );
499
500
/* Copy starting vert's edgeflag:
501
*/
502
new_vert->edgeflag = vert_prev->edgeflag;
503
*new_edge = *edge_prev;
504
}
505
}
506
507
vert_prev = vert;
508
edge_prev = edge;
509
dp_prev = dp;
510
}
511
512
/* swap in/out lists */
513
{
514
struct vertex_header **tmp = inlist;
515
inlist = outlist;
516
outlist = tmp;
517
n = outcount;
518
}
519
{
520
boolean *tmp = inEdges;
521
inEdges = outEdges;
522
outEdges = tmp;
523
}
524
525
}
526
527
/* If constant interpolated, copy provoking vertex attrib to polygon vertex[0]
528
*/
529
if (n >= 3) {
530
if (clipper->num_const_attribs) {
531
if (stage->draw->rasterizer->flatshade_first) {
532
if (inlist[0] != header->v[0]) {
533
assert(tmpnr < MAX_CLIPPED_VERTICES + 1);
534
if (tmpnr >= MAX_CLIPPED_VERTICES + 1)
535
return;
536
inlist[0] = dup_vert(stage, inlist[0], tmpnr++);
537
copy_flat(stage, inlist[0], header->v[0]);
538
}
539
}
540
else {
541
if (inlist[0] != header->v[2]) {
542
assert(tmpnr < MAX_CLIPPED_VERTICES + 1);
543
if (tmpnr >= MAX_CLIPPED_VERTICES + 1)
544
return;
545
inlist[0] = dup_vert(stage, inlist[0], tmpnr++);
546
copy_flat(stage, inlist[0], header->v[2]);
547
}
548
}
549
}
550
551
/* Emit the polygon as triangles to the setup stage:
552
*/
553
emit_poly(stage, inlist, inEdges, n, header);
554
}
555
}
556
557
558
/* Clip a line against the viewport and user clip planes.
559
*/
560
static void
561
do_clip_line(struct draw_stage *stage,
562
struct prim_header *header,
563
unsigned clipmask)
564
{
565
const struct clip_stage *clipper = clip_stage(stage);
566
struct vertex_header *v0 = header->v[0];
567
struct vertex_header *v1 = header->v[1];
568
struct vertex_header *prov_vertex;
569
float t0 = 0.0F;
570
float t1 = 0.0F;
571
struct prim_header newprim;
572
int viewport_index;
573
574
newprim.flags = header->flags;
575
576
if (stage->draw->rasterizer->flatshade_first) {
577
prov_vertex = v0;
578
}
579
else {
580
prov_vertex = v1;
581
}
582
viewport_index = draw_viewport_index(clipper->stage.draw, prov_vertex);
583
584
while (clipmask) {
585
const unsigned plane_idx = ffs(clipmask)-1;
586
const float dp0 = getclipdist(clipper, v0, plane_idx);
587
const float dp1 = getclipdist(clipper, v1, plane_idx);
588
589
if (util_is_inf_or_nan(dp0) || util_is_inf_or_nan(dp1))
590
return; //discard nan
591
592
if (dp1 < 0.0F) {
593
float t = dp1 / (dp1 - dp0);
594
t1 = MAX2(t1, t);
595
}
596
597
if (dp0 < 0.0F) {
598
float t = dp0 / (dp0 - dp1);
599
t0 = MAX2(t0, t);
600
}
601
602
if (t0 + t1 >= 1.0F)
603
return; /* discard */
604
605
clipmask &= ~(1 << plane_idx); /* turn off this plane's bit */
606
}
607
608
if (v0->clipmask) {
609
interp( clipper, stage->tmp[0], t0, v0, v1, viewport_index );
610
if (stage->draw->rasterizer->flatshade_first) {
611
copy_flat(stage, stage->tmp[0], v0); /* copy v0 color to tmp[0] */
612
}
613
else {
614
copy_flat(stage, stage->tmp[0], v1); /* copy v1 color to tmp[0] */
615
}
616
newprim.v[0] = stage->tmp[0];
617
}
618
else {
619
newprim.v[0] = v0;
620
}
621
622
if (v1->clipmask) {
623
interp( clipper, stage->tmp[1], t1, v1, v0, viewport_index );
624
if (stage->draw->rasterizer->flatshade_first) {
625
copy_flat(stage, stage->tmp[1], v0); /* copy v0 color to tmp[1] */
626
}
627
else {
628
copy_flat(stage, stage->tmp[1], v1); /* copy v1 color to tmp[1] */
629
}
630
newprim.v[1] = stage->tmp[1];
631
}
632
else {
633
newprim.v[1] = v1;
634
}
635
636
stage->next->line( stage->next, &newprim );
637
}
638
639
640
static void
641
clip_point(struct draw_stage *stage, struct prim_header *header)
642
{
643
if (header->v[0]->clipmask == 0)
644
stage->next->point( stage->next, header );
645
}
646
647
648
/*
649
* Clip points but ignore the first 4 (xy) clip planes.
650
* (Because the generated clip mask is completely unaffacted by guard band,
651
* we still need to manually evaluate the x/y planes if they are outside
652
* the guard band and not just outside the vp.)
653
*/
654
static void
655
clip_point_guard_xy(struct draw_stage *stage, struct prim_header *header)
656
{
657
unsigned clipmask = header->v[0]->clipmask;
658
if ((clipmask & 0xffffffff) == 0)
659
stage->next->point(stage->next, header);
660
else if ((clipmask & 0xfffffff0) == 0) {
661
while (clipmask) {
662
const unsigned plane_idx = ffs(clipmask)-1;
663
clipmask &= ~(1 << plane_idx); /* turn off this plane's bit */
664
/* TODO: this should really do proper guardband clipping,
665
* currently just throw out infs/nans.
666
* Also note that vertices with negative w values MUST be tossed
667
* out (not sure if proper guardband clipping would do this
668
* automatically). These would usually be captured by depth clip
669
* too but this can be disabled.
670
*/
671
if (header->v[0]->clip_pos[3] <= 0.0f ||
672
util_is_inf_or_nan(header->v[0]->clip_pos[0]) ||
673
util_is_inf_or_nan(header->v[0]->clip_pos[1]))
674
return;
675
}
676
stage->next->point(stage->next, header);
677
}
678
}
679
680
681
static void
682
clip_first_point(struct draw_stage *stage, struct prim_header *header)
683
{
684
stage->point = stage->draw->guard_band_points_xy ? clip_point_guard_xy : clip_point;
685
stage->point(stage, header);
686
}
687
688
689
static void
690
clip_line(struct draw_stage *stage, struct prim_header *header)
691
{
692
unsigned clipmask = (header->v[0]->clipmask |
693
header->v[1]->clipmask);
694
695
if (clipmask == 0) {
696
/* no clipping needed */
697
stage->next->line( stage->next, header );
698
}
699
else if ((header->v[0]->clipmask &
700
header->v[1]->clipmask) == 0) {
701
do_clip_line(stage, header, clipmask);
702
}
703
/* else, totally clipped */
704
}
705
706
707
static void
708
clip_tri(struct draw_stage *stage, struct prim_header *header)
709
{
710
unsigned clipmask = (header->v[0]->clipmask |
711
header->v[1]->clipmask |
712
header->v[2]->clipmask);
713
714
if (clipmask == 0) {
715
/* no clipping needed */
716
stage->next->tri( stage->next, header );
717
}
718
else if ((header->v[0]->clipmask &
719
header->v[1]->clipmask &
720
header->v[2]->clipmask) == 0) {
721
do_clip_tri(stage, header, clipmask);
722
}
723
}
724
725
726
static int
727
find_interp(const struct draw_fragment_shader *fs, int *indexed_interp,
728
uint semantic_name, uint semantic_index)
729
{
730
int interp;
731
/* If it's gl_{Front,Back}{,Secondary}Color, pick up the mode
732
* from the array we've filled before. */
733
if ((semantic_name == TGSI_SEMANTIC_COLOR ||
734
semantic_name == TGSI_SEMANTIC_BCOLOR) &&
735
semantic_index < 2) {
736
interp = indexed_interp[semantic_index];
737
} else if (semantic_name == TGSI_SEMANTIC_POSITION ||
738
semantic_name == TGSI_SEMANTIC_CLIPVERTEX) {
739
/* these inputs are handled specially always */
740
return -1;
741
} else {
742
/* Otherwise, search in the FS inputs, with a decent default
743
* if we don't find it.
744
* This probably only matters for layer, vpindex, culldist, maybe
745
* front_face.
746
*/
747
uint j;
748
if (semantic_name == TGSI_SEMANTIC_LAYER ||
749
semantic_name == TGSI_SEMANTIC_VIEWPORT_INDEX) {
750
interp = TGSI_INTERPOLATE_CONSTANT;
751
}
752
else {
753
interp = TGSI_INTERPOLATE_PERSPECTIVE;
754
}
755
if (fs) {
756
for (j = 0; j < fs->info.num_inputs; j++) {
757
if (semantic_name == fs->info.input_semantic_name[j] &&
758
semantic_index == fs->info.input_semantic_index[j]) {
759
interp = fs->info.input_interpolate[j];
760
break;
761
}
762
}
763
}
764
}
765
return interp;
766
}
767
768
/* Update state. Could further delay this until we hit the first
769
* primitive that really requires clipping.
770
*/
771
static void
772
clip_init_state(struct draw_stage *stage)
773
{
774
struct clip_stage *clipper = clip_stage(stage);
775
const struct draw_context *draw = stage->draw;
776
const struct draw_fragment_shader *fs = draw->fs.fragment_shader;
777
const struct tgsi_shader_info *info = draw_get_shader_info(draw);
778
uint i, j;
779
int indexed_interp[2];
780
781
clipper->pos_attr = draw_current_shader_position_output(draw);
782
clipper->have_clipdist = draw_current_shader_num_written_clipdistances(draw) > 0;
783
if (draw_current_shader_clipvertex_output(draw) != clipper->pos_attr) {
784
clipper->cv_attr = (int)draw_current_shader_clipvertex_output(draw);
785
}
786
else {
787
clipper->cv_attr = -1;
788
}
789
790
/* We need to know for each attribute what kind of interpolation is
791
* done on it (flat, smooth or noperspective). But the information
792
* is not directly accessible for outputs, only for inputs. So we
793
* have to match semantic name and index between the VS (or GS/ES)
794
* outputs and the FS inputs to get to the interpolation mode.
795
*
796
* The only hitch is with gl_FrontColor/gl_BackColor which map to
797
* gl_Color, and their Secondary versions. First there are (up to)
798
* two outputs for one input, so we tuck the information in a
799
* specific array. Second if they don't have qualifiers, the
800
* default value has to be picked from the global shade mode.
801
*
802
* Of course, if we don't have a fragment shader in the first
803
* place, defaults should be used.
804
*/
805
806
/* First pick up the interpolation mode for
807
* gl_Color/gl_SecondaryColor, with the correct default.
808
*/
809
indexed_interp[0] = indexed_interp[1] = draw->rasterizer->flatshade ?
810
TGSI_INTERPOLATE_CONSTANT : TGSI_INTERPOLATE_PERSPECTIVE;
811
812
if (fs) {
813
for (i = 0; i < fs->info.num_inputs; i++) {
814
if (fs->info.input_semantic_name[i] == TGSI_SEMANTIC_COLOR &&
815
fs->info.input_semantic_index[i] < 2) {
816
if (fs->info.input_interpolate[i] != TGSI_INTERPOLATE_COLOR)
817
indexed_interp[fs->info.input_semantic_index[i]] = fs->info.input_interpolate[i];
818
}
819
}
820
}
821
822
/* Then resolve the interpolation mode for every output attribute. */
823
824
clipper->num_const_attribs = 0;
825
clipper->num_linear_attribs = 0;
826
clipper->num_perspect_attribs = 0;
827
for (i = 0; i < info->num_outputs; i++) {
828
/* Find the interpolation mode for a specific attribute */
829
int interp = find_interp(fs, indexed_interp,
830
info->output_semantic_name[i],
831
info->output_semantic_index[i]);
832
switch (interp) {
833
case TGSI_INTERPOLATE_CONSTANT:
834
clipper->const_attribs[clipper->num_const_attribs] = i;
835
clipper->num_const_attribs++;
836
break;
837
case TGSI_INTERPOLATE_LINEAR:
838
clipper->linear_attribs[clipper->num_linear_attribs] = i;
839
clipper->num_linear_attribs++;
840
break;
841
case TGSI_INTERPOLATE_PERSPECTIVE:
842
clipper->perspect_attribs[clipper->num_perspect_attribs] = i;
843
clipper->num_perspect_attribs++;
844
break;
845
case TGSI_INTERPOLATE_COLOR:
846
if (draw->rasterizer->flatshade) {
847
clipper->const_attribs[clipper->num_const_attribs] = i;
848
clipper->num_const_attribs++;
849
} else {
850
clipper->perspect_attribs[clipper->num_perspect_attribs] = i;
851
clipper->num_perspect_attribs++;
852
}
853
break;
854
default:
855
assert(interp == -1);
856
break;
857
}
858
}
859
/* Search the extra vertex attributes */
860
for (j = 0; j < draw->extra_shader_outputs.num; j++) {
861
/* Find the interpolation mode for a specific attribute */
862
int interp = find_interp(fs, indexed_interp,
863
draw->extra_shader_outputs.semantic_name[j],
864
draw->extra_shader_outputs.semantic_index[j]);
865
switch (interp) {
866
case TGSI_INTERPOLATE_CONSTANT:
867
clipper->const_attribs[clipper->num_const_attribs] = i + j;
868
clipper->num_const_attribs++;
869
break;
870
case TGSI_INTERPOLATE_LINEAR:
871
clipper->linear_attribs[clipper->num_linear_attribs] = i + j;
872
clipper->num_linear_attribs++;
873
break;
874
case TGSI_INTERPOLATE_PERSPECTIVE:
875
clipper->perspect_attribs[clipper->num_perspect_attribs] = i + j;
876
clipper->num_perspect_attribs++;
877
break;
878
default:
879
assert(interp == -1);
880
break;
881
}
882
}
883
884
stage->tri = clip_tri;
885
stage->line = clip_line;
886
}
887
888
889
890
static void clip_first_tri(struct draw_stage *stage,
891
struct prim_header *header)
892
{
893
clip_init_state( stage );
894
stage->tri( stage, header );
895
}
896
897
static void clip_first_line(struct draw_stage *stage,
898
struct prim_header *header)
899
{
900
clip_init_state( stage );
901
stage->line( stage, header );
902
}
903
904
905
static void clip_flush(struct draw_stage *stage, unsigned flags)
906
{
907
stage->tri = clip_first_tri;
908
stage->line = clip_first_line;
909
stage->next->flush( stage->next, flags );
910
}
911
912
913
static void clip_reset_stipple_counter(struct draw_stage *stage)
914
{
915
stage->next->reset_stipple_counter( stage->next );
916
}
917
918
919
static void clip_destroy(struct draw_stage *stage)
920
{
921
draw_free_temp_verts( stage );
922
FREE( stage );
923
}
924
925
926
/**
927
* Allocate a new clipper stage.
928
* \return pointer to new stage object
929
*/
930
struct draw_stage *draw_clip_stage(struct draw_context *draw)
931
{
932
struct clip_stage *clipper = CALLOC_STRUCT(clip_stage);
933
if (!clipper)
934
goto fail;
935
936
clipper->stage.draw = draw;
937
clipper->stage.name = "clipper";
938
clipper->stage.point = clip_first_point;
939
clipper->stage.line = clip_first_line;
940
clipper->stage.tri = clip_first_tri;
941
clipper->stage.flush = clip_flush;
942
clipper->stage.reset_stipple_counter = clip_reset_stipple_counter;
943
clipper->stage.destroy = clip_destroy;
944
945
clipper->plane = draw->plane;
946
947
if (!draw_alloc_temp_verts( &clipper->stage, MAX_CLIPPED_VERTICES+1 ))
948
goto fail;
949
950
return &clipper->stage;
951
952
fail:
953
if (clipper)
954
clipper->stage.destroy( &clipper->stage );
955
956
return NULL;
957
}
958
959