1bf215546Sopenharmony_ci/************************************************************************** 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright 2010, VMware, inc. 4bf215546Sopenharmony_ci * All Rights Reserved. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 12bf215546Sopenharmony_ci * the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 16bf215546Sopenharmony_ci * of the Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci **************************************************************************/ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include "util/u_bitcast.h" 29bf215546Sopenharmony_ci#include <math.h> 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_cistatic boolean TAG(do_cliptest)( struct pt_post_vs *pvs, 32bf215546Sopenharmony_ci struct draw_vertex_info *info, 33bf215546Sopenharmony_ci const struct draw_prim_info *prim_info ) 34bf215546Sopenharmony_ci{ 35bf215546Sopenharmony_ci struct vertex_header *out = info->verts; 36bf215546Sopenharmony_ci /* const */ float (*plane)[4] = pvs->draw->plane; 37bf215546Sopenharmony_ci const unsigned pos = draw_current_shader_position_output(pvs->draw); 38bf215546Sopenharmony_ci const unsigned cv = draw_current_shader_clipvertex_output(pvs->draw); 39bf215546Sopenharmony_ci unsigned cd[2]; 40bf215546Sopenharmony_ci const unsigned ef = pvs->draw->vs.edgeflag_output; 41bf215546Sopenharmony_ci unsigned ucp_enable = pvs->draw->rasterizer->clip_plane_enable; 42bf215546Sopenharmony_ci unsigned flags = (FLAGS); 43bf215546Sopenharmony_ci unsigned need_pipeline = 0; 44bf215546Sopenharmony_ci unsigned j; 45bf215546Sopenharmony_ci unsigned i; 46bf215546Sopenharmony_ci bool have_cd = false; 47bf215546Sopenharmony_ci bool uses_vp_idx = draw_current_shader_uses_viewport_index(pvs->draw); 48bf215546Sopenharmony_ci unsigned viewport_index_output = 49bf215546Sopenharmony_ci draw_current_shader_viewport_index_output(pvs->draw); 50bf215546Sopenharmony_ci int viewport_index = 0; 51bf215546Sopenharmony_ci int num_written_clipdistance = 52bf215546Sopenharmony_ci draw_current_shader_num_written_clipdistances(pvs->draw); 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_ci if (uses_vp_idx) { 55bf215546Sopenharmony_ci viewport_index = u_bitcast_f2u(out->data[viewport_index_output][0]); 56bf215546Sopenharmony_ci viewport_index = draw_clamp_viewport_idx(viewport_index); 57bf215546Sopenharmony_ci } 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci cd[0] = draw_current_shader_ccdistance_output(pvs->draw, 0); 60bf215546Sopenharmony_ci cd[1] = draw_current_shader_ccdistance_output(pvs->draw, 1); 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci if (cd[0] != pos || cd[1] != pos) 63bf215546Sopenharmony_ci have_cd = true; 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_ci /* If clipdistance semantic has been written by the shader 66bf215546Sopenharmony_ci * that means we're expected to do 'user plane clipping' */ 67bf215546Sopenharmony_ci if (num_written_clipdistance && !(flags & DO_CLIP_USER)) { 68bf215546Sopenharmony_ci flags |= DO_CLIP_USER; 69bf215546Sopenharmony_ci ucp_enable = (1 << num_written_clipdistance) - 1; 70bf215546Sopenharmony_ci } 71bf215546Sopenharmony_ci 72bf215546Sopenharmony_ci assert(pos != -1); 73bf215546Sopenharmony_ci unsigned prim_idx = 0, prim_vert_idx = 0; 74bf215546Sopenharmony_ci for (j = 0; j < info->count; j++) { 75bf215546Sopenharmony_ci float *position = out->data[pos]; 76bf215546Sopenharmony_ci unsigned mask = 0x0; 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci if (uses_vp_idx) { 79bf215546Sopenharmony_ci /* only change the viewport_index for the leading vertex */ 80bf215546Sopenharmony_ci if (prim_vert_idx == (prim_info->primitive_lengths[prim_idx])) { 81bf215546Sopenharmony_ci prim_idx++; 82bf215546Sopenharmony_ci prim_vert_idx = 0; 83bf215546Sopenharmony_ci viewport_index = u_bitcast_f2u(out->data[viewport_index_output][0]); 84bf215546Sopenharmony_ci viewport_index = draw_clamp_viewport_idx(viewport_index); 85bf215546Sopenharmony_ci } 86bf215546Sopenharmony_ci prim_vert_idx++; 87bf215546Sopenharmony_ci } 88bf215546Sopenharmony_ci float *scale = pvs->draw->viewports[viewport_index].scale; 89bf215546Sopenharmony_ci float *trans = pvs->draw->viewports[viewport_index].translate; 90bf215546Sopenharmony_ci initialize_vertex_header(out); 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci if (flags & (DO_CLIP_XY | DO_CLIP_XY_GUARD_BAND | 93bf215546Sopenharmony_ci DO_CLIP_FULL_Z | DO_CLIP_HALF_Z | DO_CLIP_USER)) { 94bf215546Sopenharmony_ci float *clipvertex = position; 95bf215546Sopenharmony_ci 96bf215546Sopenharmony_ci if ((flags & DO_CLIP_USER) && cv != pos) { 97bf215546Sopenharmony_ci assert(cv != -1); 98bf215546Sopenharmony_ci clipvertex = out->data[cv]; 99bf215546Sopenharmony_ci } 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_ci for (i = 0; i < 4; i++) { 102bf215546Sopenharmony_ci out->clip_pos[i] = position[i]; 103bf215546Sopenharmony_ci } 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci /* Be careful with NaNs. Comparisons must be true for them. */ 106bf215546Sopenharmony_ci /* Do the hardwired planes first: 107bf215546Sopenharmony_ci */ 108bf215546Sopenharmony_ci if (flags & DO_CLIP_XY_GUARD_BAND) { 109bf215546Sopenharmony_ci if (!(-0.50 * position[0] + position[3] >= 0)) mask |= (1<<0); 110bf215546Sopenharmony_ci if (!( 0.50 * position[0] + position[3] >= 0)) mask |= (1<<1); 111bf215546Sopenharmony_ci if (!(-0.50 * position[1] + position[3] >= 0)) mask |= (1<<2); 112bf215546Sopenharmony_ci if (!( 0.50 * position[1] + position[3] >= 0)) mask |= (1<<3); 113bf215546Sopenharmony_ci } 114bf215546Sopenharmony_ci else if (flags & DO_CLIP_XY) { 115bf215546Sopenharmony_ci if (!(-position[0] + position[3] >= 0)) mask |= (1<<0); 116bf215546Sopenharmony_ci if (!( position[0] + position[3] >= 0)) mask |= (1<<1); 117bf215546Sopenharmony_ci if (!(-position[1] + position[3] >= 0)) mask |= (1<<2); 118bf215546Sopenharmony_ci if (!( position[1] + position[3] >= 0)) mask |= (1<<3); 119bf215546Sopenharmony_ci } 120bf215546Sopenharmony_ci 121bf215546Sopenharmony_ci /* Clip Z planes according to full cube, half cube or none. 122bf215546Sopenharmony_ci */ 123bf215546Sopenharmony_ci if (flags & DO_CLIP_FULL_Z) { 124bf215546Sopenharmony_ci if (!( position[2] + position[3] >= 0)) mask |= (1<<4); 125bf215546Sopenharmony_ci if (!(-position[2] + position[3] >= 0)) mask |= (1<<5); 126bf215546Sopenharmony_ci } 127bf215546Sopenharmony_ci else if (flags & DO_CLIP_HALF_Z) { 128bf215546Sopenharmony_ci if (!( position[2] >= 0)) mask |= (1<<4); 129bf215546Sopenharmony_ci if (!(-position[2] + position[3] >= 0)) mask |= (1<<5); 130bf215546Sopenharmony_ci } 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ci if (flags & DO_CLIP_USER) { 133bf215546Sopenharmony_ci unsigned ucp_mask = ucp_enable; 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci while (ucp_mask) { 136bf215546Sopenharmony_ci unsigned plane_idx = ffs(ucp_mask)-1; 137bf215546Sopenharmony_ci ucp_mask &= ~(1 << plane_idx); 138bf215546Sopenharmony_ci plane_idx += 6; 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci /* 141bf215546Sopenharmony_ci * for user clipping check if we have a clip distance output 142bf215546Sopenharmony_ci * and the shader has written to it, otherwise use clipvertex 143bf215546Sopenharmony_ci * to decide when the plane is clipping. 144bf215546Sopenharmony_ci */ 145bf215546Sopenharmony_ci if (have_cd && num_written_clipdistance) { 146bf215546Sopenharmony_ci float clipdist; 147bf215546Sopenharmony_ci i = plane_idx - 6; 148bf215546Sopenharmony_ci /* first four clip distance in first vector etc. */ 149bf215546Sopenharmony_ci if (i < 4) 150bf215546Sopenharmony_ci clipdist = out->data[cd[0]][i]; 151bf215546Sopenharmony_ci else 152bf215546Sopenharmony_ci clipdist = out->data[cd[1]][i-4]; 153bf215546Sopenharmony_ci if (clipdist < 0 || util_is_inf_or_nan(clipdist)) 154bf215546Sopenharmony_ci mask |= 1 << plane_idx; 155bf215546Sopenharmony_ci } else { 156bf215546Sopenharmony_ci if (!(dot4(clipvertex, plane[plane_idx]) >= 0)) 157bf215546Sopenharmony_ci mask |= 1 << plane_idx; 158bf215546Sopenharmony_ci } 159bf215546Sopenharmony_ci } 160bf215546Sopenharmony_ci } 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_ci out->clipmask = mask; 163bf215546Sopenharmony_ci need_pipeline |= out->clipmask; 164bf215546Sopenharmony_ci } 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci /* 167bf215546Sopenharmony_ci * Transform the vertex position from clip coords to window coords, 168bf215546Sopenharmony_ci * if the vertex is unclipped. 169bf215546Sopenharmony_ci */ 170bf215546Sopenharmony_ci if ((flags & DO_VIEWPORT) && mask == 0) 171bf215546Sopenharmony_ci { 172bf215546Sopenharmony_ci /* divide by w */ 173bf215546Sopenharmony_ci float w = 1.0f / position[3]; 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_ci /* Viewport mapping */ 176bf215546Sopenharmony_ci position[0] = position[0] * w * scale[0] + trans[0]; 177bf215546Sopenharmony_ci position[1] = position[1] * w * scale[1] + trans[1]; 178bf215546Sopenharmony_ci position[2] = position[2] * w * scale[2] + trans[2]; 179bf215546Sopenharmony_ci position[3] = w; 180bf215546Sopenharmony_ci } 181bf215546Sopenharmony_ci#ifdef DEBUG 182bf215546Sopenharmony_ci /* For debug builds, set the clipped vertex's window coordinate 183bf215546Sopenharmony_ci * to NaN to help catch potential errors later. 184bf215546Sopenharmony_ci */ 185bf215546Sopenharmony_ci else { 186bf215546Sopenharmony_ci position[0] = 187bf215546Sopenharmony_ci position[1] = 188bf215546Sopenharmony_ci position[2] = 189bf215546Sopenharmony_ci position[3] = NAN; 190bf215546Sopenharmony_ci } 191bf215546Sopenharmony_ci#endif 192bf215546Sopenharmony_ci 193bf215546Sopenharmony_ci if ((flags & DO_EDGEFLAG) && ef) { 194bf215546Sopenharmony_ci const float *edgeflag = out->data[ef]; 195bf215546Sopenharmony_ci out->edgeflag = !(edgeflag[0] != 1.0f); 196bf215546Sopenharmony_ci need_pipeline |= !out->edgeflag; 197bf215546Sopenharmony_ci } 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci out = (struct vertex_header *)( (char *)out + info->stride ); 200bf215546Sopenharmony_ci } 201bf215546Sopenharmony_ci return need_pipeline != 0; 202bf215546Sopenharmony_ci} 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci#undef FLAGS 206bf215546Sopenharmony_ci#undef TAG 207