1 /* 2 Copyright (C) Intel Corp. 2006. All Rights Reserved. 3 Intel funded Tungsten Graphics to 4 develop this 3D driver. 5 6 Permission is hereby granted, free of charge, to any person obtaining 7 a 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, sublicense, 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 16 portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 26 **********************************************************************/ 27 /* 28 * Authors: 29 * Keith Whitwell <keithw (at) vmware.com> 30 */ 31 32 #include "main/macros.h" 33 #include "main/enums.h" 34 #include "program/program.h" 35 36 #include "intel_batchbuffer.h" 37 38 #include "brw_defines.h" 39 #include "brw_context.h" 40 #include "brw_eu.h" 41 #include "brw_clip.h" 42 43 44 45 static void brw_clip_line_alloc_regs( struct brw_clip_compile *c ) 46 { 47 const struct gen_device_info *devinfo = c->func.devinfo; 48 GLuint i = 0,j; 49 50 /* Register usage is static, precompute here: 51 */ 52 c->reg.R0 = retype(brw_vec8_grf(i, 0), BRW_REGISTER_TYPE_UD); i++; 53 54 if (c->key.nr_userclip) { 55 c->reg.fixed_planes = brw_vec4_grf(i, 0); 56 i += (6 + c->key.nr_userclip + 1) / 2; 57 58 c->prog_data.curb_read_length = (6 + c->key.nr_userclip + 1) / 2; 59 } 60 else 61 c->prog_data.curb_read_length = 0; 62 63 64 /* Payload vertices plus space for more generated vertices: 65 */ 66 for (j = 0; j < 4; j++) { 67 c->reg.vertex[j] = brw_vec4_grf(i, 0); 68 i += c->nr_regs; 69 } 70 71 c->reg.t = brw_vec1_grf(i, 0); 72 c->reg.t0 = brw_vec1_grf(i, 1); 73 c->reg.t1 = brw_vec1_grf(i, 2); 74 c->reg.planemask = retype(brw_vec1_grf(i, 3), BRW_REGISTER_TYPE_UD); 75 c->reg.plane_equation = brw_vec4_grf(i, 4); 76 i++; 77 78 c->reg.dp0 = brw_vec1_grf(i, 0); /* fixme - dp4 will clobber r.1,2,3 */ 79 c->reg.dp1 = brw_vec1_grf(i, 4); 80 i++; 81 82 if (!c->key.nr_userclip) { 83 c->reg.fixed_planes = brw_vec8_grf(i, 0); 84 i++; 85 } 86 87 c->reg.vertex_src_mask = retype(brw_vec1_grf(i, 0), BRW_REGISTER_TYPE_UD); 88 c->reg.clipdistance_offset = retype(brw_vec1_grf(i, 1), BRW_REGISTER_TYPE_W); 89 i++; 90 91 if (devinfo->gen == 5) { 92 c->reg.ff_sync = retype(brw_vec1_grf(i, 0), BRW_REGISTER_TYPE_UD); 93 i++; 94 } 95 96 c->first_tmp = i; 97 c->last_tmp = i; 98 99 c->prog_data.urb_read_length = c->nr_regs; /* ? */ 100 c->prog_data.total_grf = i; 101 } 102 103 104 /* Line clipping, more or less following the following algorithm: 105 * 106 * for (p=0;p<MAX_PLANES;p++) { 107 * if (clipmask & (1 << p)) { 108 * GLfloat dp0 = DOTPROD( vtx0, plane[p] ); 109 * GLfloat dp1 = DOTPROD( vtx1, plane[p] ); 110 * 111 * if (dp1 < 0.0f) { 112 * GLfloat t = dp1 / (dp1 - dp0); 113 * if (t > t1) t1 = t; 114 * } else { 115 * GLfloat t = dp0 / (dp0 - dp1); 116 * if (t > t0) t0 = t; 117 * } 118 * 119 * if (t0 + t1 >= 1.0) 120 * return; 121 * } 122 * } 123 * 124 * interp( ctx, newvtx0, vtx0, vtx1, t0 ); 125 * interp( ctx, newvtx1, vtx1, vtx0, t1 ); 126 * 127 */ 128 static void clip_and_emit_line( struct brw_clip_compile *c ) 129 { 130 struct brw_codegen *p = &c->func; 131 struct brw_indirect vtx0 = brw_indirect(0, 0); 132 struct brw_indirect vtx1 = brw_indirect(1, 0); 133 struct brw_indirect newvtx0 = brw_indirect(2, 0); 134 struct brw_indirect newvtx1 = brw_indirect(3, 0); 135 struct brw_indirect plane_ptr = brw_indirect(4, 0); 136 struct brw_reg v1_null_ud = retype(vec1(brw_null_reg()), BRW_REGISTER_TYPE_UD); 137 GLuint hpos_offset = brw_varying_to_offset(&c->vue_map, VARYING_SLOT_POS); 138 GLint clipdist0_offset = c->key.nr_userclip 139 ? brw_varying_to_offset(&c->vue_map, VARYING_SLOT_CLIP_DIST0) 140 : 0; 141 142 brw_MOV(p, get_addr_reg(vtx0), brw_address(c->reg.vertex[0])); 143 brw_MOV(p, get_addr_reg(vtx1), brw_address(c->reg.vertex[1])); 144 brw_MOV(p, get_addr_reg(newvtx0), brw_address(c->reg.vertex[2])); 145 brw_MOV(p, get_addr_reg(newvtx1), brw_address(c->reg.vertex[3])); 146 brw_MOV(p, get_addr_reg(plane_ptr), brw_clip_plane0_address(c)); 147 148 /* Note: init t0, t1 together: 149 */ 150 brw_MOV(p, vec2(c->reg.t0), brw_imm_f(0)); 151 152 brw_clip_init_planes(c); 153 brw_clip_init_clipmask(c); 154 155 /* -ve rhw workaround */ 156 if (p->devinfo->has_negative_rhw_bug) { 157 brw_AND(p, brw_null_reg(), get_element_ud(c->reg.R0, 2), 158 brw_imm_ud(1<<20)); 159 brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ); 160 brw_OR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud(0x3f)); 161 brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL); 162 } 163 164 /* Set the initial vertex source mask: The first 6 planes are the bounds 165 * of the view volume; the next 8 planes are the user clipping planes. 166 */ 167 brw_MOV(p, c->reg.vertex_src_mask, brw_imm_ud(0x3fc0)); 168 169 /* Set the initial clipdistance offset to be 6 floats before gl_ClipDistance[0]. 170 * We'll increment 6 times before we start hitting actual user clipping. */ 171 brw_MOV(p, c->reg.clipdistance_offset, brw_imm_d(clipdist0_offset - 6*sizeof(float))); 172 173 brw_DO(p, BRW_EXECUTE_1); 174 { 175 /* if (planemask & 1) 176 */ 177 brw_AND(p, v1_null_ud, c->reg.planemask, brw_imm_ud(1)); 178 brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ); 179 180 brw_IF(p, BRW_EXECUTE_1); 181 { 182 brw_AND(p, v1_null_ud, c->reg.vertex_src_mask, brw_imm_ud(1)); 183 brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ); 184 brw_IF(p, BRW_EXECUTE_1); 185 { 186 /* user clip distance: just fetch the correct float from each vertex */ 187 struct brw_indirect temp_ptr = brw_indirect(7, 0); 188 brw_ADD(p, get_addr_reg(temp_ptr), get_addr_reg(vtx0), c->reg.clipdistance_offset); 189 brw_MOV(p, c->reg.dp0, deref_1f(temp_ptr, 0)); 190 brw_ADD(p, get_addr_reg(temp_ptr), get_addr_reg(vtx1), c->reg.clipdistance_offset); 191 brw_MOV(p, c->reg.dp1, deref_1f(temp_ptr, 0)); 192 } 193 brw_ELSE(p); 194 { 195 /* fixed plane: fetch the hpos, dp4 against the plane. */ 196 if (c->key.nr_userclip) 197 brw_MOV(p, c->reg.plane_equation, deref_4f(plane_ptr, 0)); 198 else 199 brw_MOV(p, c->reg.plane_equation, deref_4b(plane_ptr, 0)); 200 201 brw_DP4(p, vec4(c->reg.dp0), deref_4f(vtx0, hpos_offset), c->reg.plane_equation); 202 brw_DP4(p, vec4(c->reg.dp1), deref_4f(vtx1, hpos_offset), c->reg.plane_equation); 203 } 204 brw_ENDIF(p); 205 206 brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_L, vec1(c->reg.dp1), brw_imm_f(0.0f)); 207 208 brw_IF(p, BRW_EXECUTE_1); 209 { 210 /* 211 * Both can be negative on GM965/G965 due to RHW workaround 212 * if so, this object should be rejected. 213 */ 214 if (p->devinfo->has_negative_rhw_bug) { 215 brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_LE, c->reg.dp0, brw_imm_f(0.0)); 216 brw_IF(p, BRW_EXECUTE_1); 217 { 218 brw_clip_kill_thread(c); 219 } 220 brw_ENDIF(p); 221 } 222 223 brw_ADD(p, c->reg.t, c->reg.dp1, negate(c->reg.dp0)); 224 brw_math_invert(p, c->reg.t, c->reg.t); 225 brw_MUL(p, c->reg.t, c->reg.t, c->reg.dp1); 226 227 brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_G, c->reg.t, c->reg.t1 ); 228 brw_MOV(p, c->reg.t1, c->reg.t); 229 brw_inst_set_pred_control(p->devinfo, brw_last_inst, 230 BRW_PREDICATE_NORMAL); 231 } 232 brw_ELSE(p); 233 { 234 /* Coming back in. We know that both cannot be negative 235 * because the line would have been culled in that case. 236 */ 237 238 /* If both are positive, do nothing */ 239 /* Only on GM965/G965 */ 240 if (p->devinfo->has_negative_rhw_bug) { 241 brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_L, c->reg.dp0, brw_imm_f(0.0)); 242 brw_IF(p, BRW_EXECUTE_1); 243 } 244 245 { 246 brw_ADD(p, c->reg.t, c->reg.dp0, negate(c->reg.dp1)); 247 brw_math_invert(p, c->reg.t, c->reg.t); 248 brw_MUL(p, c->reg.t, c->reg.t, c->reg.dp0); 249 250 brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_G, c->reg.t, c->reg.t0 ); 251 brw_MOV(p, c->reg.t0, c->reg.t); 252 brw_inst_set_pred_control(p->devinfo, brw_last_inst, 253 BRW_PREDICATE_NORMAL); 254 } 255 256 if (p->devinfo->has_negative_rhw_bug) { 257 brw_ENDIF(p); 258 } 259 } 260 brw_ENDIF(p); 261 } 262 brw_ENDIF(p); 263 264 /* plane_ptr++; 265 */ 266 brw_ADD(p, get_addr_reg(plane_ptr), get_addr_reg(plane_ptr), brw_clip_plane_stride(c)); 267 268 /* while (planemask>>=1) != 0 269 */ 270 brw_SHR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud(1)); 271 brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ); 272 brw_SHR(p, c->reg.vertex_src_mask, c->reg.vertex_src_mask, brw_imm_ud(1)); 273 brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL); 274 brw_ADD(p, c->reg.clipdistance_offset, c->reg.clipdistance_offset, brw_imm_w(sizeof(float))); 275 brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL); 276 } 277 brw_WHILE(p); 278 brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL); 279 280 brw_ADD(p, c->reg.t, c->reg.t0, c->reg.t1); 281 brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_L, c->reg.t, brw_imm_f(1.0)); 282 brw_IF(p, BRW_EXECUTE_1); 283 { 284 brw_clip_interp_vertex(c, newvtx0, vtx0, vtx1, c->reg.t0, false); 285 brw_clip_interp_vertex(c, newvtx1, vtx1, vtx0, c->reg.t1, false); 286 287 brw_clip_emit_vue(c, newvtx0, BRW_URB_WRITE_ALLOCATE_COMPLETE, 288 (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT) 289 | URB_WRITE_PRIM_START); 290 brw_clip_emit_vue(c, newvtx1, BRW_URB_WRITE_EOT_COMPLETE, 291 (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT) 292 | URB_WRITE_PRIM_END); 293 } 294 brw_ENDIF(p); 295 brw_clip_kill_thread(c); 296 } 297 298 299 300 void brw_emit_line_clip( struct brw_clip_compile *c ) 301 { 302 brw_clip_line_alloc_regs(c); 303 brw_clip_init_ff_sync(c); 304 305 if (c->key.contains_flat_varying) { 306 if (c->key.pv_first) 307 brw_clip_copy_flatshaded_attributes(c, 1, 0); 308 else 309 brw_clip_copy_flatshaded_attributes(c, 0, 1); 310 } 311 312 clip_and_emit_line(c); 313 } 314