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 polygon offset state 30 * 31 * \author Keith Whitwell <keithw (at) vmware.com> 32 * \author Brian Paul 33 */ 34 35 #include "util/u_format.h" 36 #include "util/u_math.h" 37 #include "util/u_memory.h" 38 #include "draw_pipe.h" 39 40 41 42 struct offset_stage { 43 struct draw_stage stage; 44 45 float scale; 46 float units; 47 float clamp; 48 }; 49 50 51 52 static inline struct offset_stage *offset_stage( struct draw_stage *stage ) 53 { 54 return (struct offset_stage *) stage; 55 } 56 57 58 59 60 61 /** 62 * Offset tri Z. Some hardware can handle this, but not usually when 63 * doing unfilled rendering. 64 */ 65 static void do_offset_tri( struct draw_stage *stage, 66 struct prim_header *header ) 67 { 68 const unsigned pos = draw_current_shader_position_output(stage->draw); 69 struct offset_stage *offset = offset_stage(stage); 70 float inv_det = 1.0f / header->det; 71 72 /* Window coords: 73 */ 74 float *v0 = header->v[0]->data[pos]; 75 float *v1 = header->v[1]->data[pos]; 76 float *v2 = header->v[2]->data[pos]; 77 78 /* edge vectors e = v0 - v2, f = v1 - v2 */ 79 float ex = v0[0] - v2[0]; 80 float ey = v0[1] - v2[1]; 81 float ez = v0[2] - v2[2]; 82 float fx = v1[0] - v2[0]; 83 float fy = v1[1] - v2[1]; 84 float fz = v1[2] - v2[2]; 85 86 /* (a,b) = cross(e,f).xy */ 87 float a = ey*fz - ez*fy; 88 float b = ez*fx - ex*fz; 89 90 float dzdx = fabsf(a * inv_det); 91 float dzdy = fabsf(b * inv_det); 92 93 float zoffset, mult; 94 95 mult = MAX2(dzdx, dzdy) * offset->scale; 96 97 if (stage->draw->floating_point_depth) { 98 float bias; 99 union fi maxz; 100 maxz.f = MAX3(v0[2], v1[2], v2[2]); 101 /* just do the math directly on shifted number */ 102 maxz.ui &= 0xff << 23; 103 maxz.i -= 23 << 23; 104 /* Clamping to zero means mrd will be zero for very small numbers, 105 * but specs do not indicate this should be prevented by clamping 106 * mrd to smallest normal number instead. */ 107 maxz.i = MAX2(maxz.i, 0); 108 109 bias = offset->units * maxz.f; 110 zoffset = bias + mult; 111 } else { 112 zoffset = offset->units + mult; 113 } 114 115 if (offset->clamp) 116 zoffset = (offset->clamp < 0.0f) ? MAX2(zoffset, offset->clamp) : 117 MIN2(zoffset, offset->clamp); 118 119 /* 120 * Note: we're applying the offset and clamping per-vertex. 121 * Ideally, the offset is applied per-fragment prior to fragment shading. 122 */ 123 v0[2] = CLAMP(v0[2] + zoffset, 0.0f, 1.0f); 124 v1[2] = CLAMP(v1[2] + zoffset, 0.0f, 1.0f); 125 v2[2] = CLAMP(v2[2] + zoffset, 0.0f, 1.0f); 126 127 stage->next->tri( stage->next, header ); 128 } 129 130 131 static void offset_tri( struct draw_stage *stage, 132 struct prim_header *header ) 133 { 134 struct prim_header tmp; 135 136 tmp.det = header->det; 137 tmp.flags = header->flags; 138 tmp.pad = header->pad; 139 tmp.v[0] = dup_vert(stage, header->v[0], 0); 140 tmp.v[1] = dup_vert(stage, header->v[1], 1); 141 tmp.v[2] = dup_vert(stage, header->v[2], 2); 142 143 do_offset_tri( stage, &tmp ); 144 } 145 146 147 static void offset_first_tri( struct draw_stage *stage, 148 struct prim_header *header ) 149 { 150 struct offset_stage *offset = offset_stage(stage); 151 const struct pipe_rasterizer_state *rast = stage->draw->rasterizer; 152 unsigned fill_mode = rast->fill_front; 153 boolean do_offset; 154 155 if (rast->fill_back != rast->fill_front) { 156 /* Need to check for back-facing triangle */ 157 boolean ccw = header->det < 0.0f; 158 if (ccw != rast->front_ccw) 159 fill_mode = rast->fill_back; 160 } 161 162 /* Now determine if we need to do offsetting for the point/line/fill mode */ 163 switch (fill_mode) { 164 case PIPE_POLYGON_MODE_FILL: 165 do_offset = rast->offset_tri; 166 break; 167 case PIPE_POLYGON_MODE_LINE: 168 do_offset = rast->offset_line; 169 break; 170 case PIPE_POLYGON_MODE_POINT: 171 do_offset = rast->offset_point; 172 break; 173 default: 174 assert(!"invalid fill_mode in offset_first_tri()"); 175 do_offset = rast->offset_tri; 176 } 177 178 if (do_offset) { 179 offset->scale = rast->offset_scale; 180 offset->clamp = rast->offset_clamp; 181 182 /* 183 * If depth is floating point, depth bias is calculated with respect 184 * to the primitive's maximum Z value. Retain the original depth bias 185 * value until that stage. 186 */ 187 if (stage->draw->floating_point_depth) { 188 offset->units = (float) rast->offset_units; 189 } else { 190 offset->units = (float) (rast->offset_units * stage->draw->mrd); 191 } 192 } 193 else { 194 offset->scale = 0.0f; 195 offset->clamp = 0.0f; 196 offset->units = 0.0f; 197 } 198 199 200 stage->tri = offset_tri; 201 stage->tri( stage, header ); 202 } 203 204 205 206 207 static void offset_flush( struct draw_stage *stage, 208 unsigned flags ) 209 { 210 stage->tri = offset_first_tri; 211 stage->next->flush( stage->next, flags ); 212 } 213 214 215 static void offset_reset_stipple_counter( struct draw_stage *stage ) 216 { 217 stage->next->reset_stipple_counter( stage->next ); 218 } 219 220 221 static void offset_destroy( struct draw_stage *stage ) 222 { 223 draw_free_temp_verts( stage ); 224 FREE( stage ); 225 } 226 227 228 /** 229 * Create polygon offset drawing stage. 230 */ 231 struct draw_stage *draw_offset_stage( struct draw_context *draw ) 232 { 233 struct offset_stage *offset = CALLOC_STRUCT(offset_stage); 234 if (!offset) 235 goto fail; 236 237 offset->stage.draw = draw; 238 offset->stage.name = "offset"; 239 offset->stage.next = NULL; 240 offset->stage.point = draw_pipe_passthrough_point; 241 offset->stage.line = draw_pipe_passthrough_line; 242 offset->stage.tri = offset_first_tri; 243 offset->stage.flush = offset_flush; 244 offset->stage.reset_stipple_counter = offset_reset_stipple_counter; 245 offset->stage.destroy = offset_destroy; 246 247 if (!draw_alloc_temp_verts( &offset->stage, 3 )) 248 goto fail; 249 250 return &offset->stage; 251 252 fail: 253 if (offset) 254 offset->stage.destroy( &offset->stage ); 255 256 return NULL; 257 } 258