1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2019 Advanced Micro Devices, Inc. 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 6bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 7bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 8bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 9bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 10bf215546Sopenharmony_ci * the following conditions: 11bf215546Sopenharmony_ci * 12bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 15bf215546Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 16bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 17bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 18bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 19bf215546Sopenharmony_ci * 20bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 21bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 22bf215546Sopenharmony_ci * of the Software. 23bf215546Sopenharmony_ci * 24bf215546Sopenharmony_ci */ 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include "ac_llvm_cull.h" 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include <llvm-c/Core.h> 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_cistruct ac_position_w_info { 31bf215546Sopenharmony_ci /* If a primitive intersects the W=0 plane, it causes a reflection 32bf215546Sopenharmony_ci * of the determinant used for face culling. Every vertex behind 33bf215546Sopenharmony_ci * the W=0 plane negates the determinant, so having 2 vertices behind 34bf215546Sopenharmony_ci * the plane has no effect. This is i1 true if the determinant should be 35bf215546Sopenharmony_ci * negated. 36bf215546Sopenharmony_ci */ 37bf215546Sopenharmony_ci LLVMValueRef w_reflection; 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci /* If we simplify the "-w <= p <= w" view culling equation, we get 40bf215546Sopenharmony_ci * "-w <= w", which can't be satisfied when w is negative. 41bf215546Sopenharmony_ci * In perspective projection, a negative W means that the primitive 42bf215546Sopenharmony_ci * is behind the viewer, but the equation is independent of the type 43bf215546Sopenharmony_ci * of projection. 44bf215546Sopenharmony_ci * 45bf215546Sopenharmony_ci * w_accepted is false when all W are negative and therefore 46bf215546Sopenharmony_ci * the primitive is invisible. 47bf215546Sopenharmony_ci */ 48bf215546Sopenharmony_ci LLVMValueRef w_accepted; 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ci /* The bounding box culling doesn't work and should be skipped when this is true. */ 51bf215546Sopenharmony_ci LLVMValueRef any_w_negative; 52bf215546Sopenharmony_ci}; 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_cistatic void ac_analyze_position_w(struct ac_llvm_context *ctx, LLVMValueRef pos[3][4], 55bf215546Sopenharmony_ci struct ac_position_w_info *w, unsigned num_vertices) 56bf215546Sopenharmony_ci{ 57bf215546Sopenharmony_ci LLVMBuilderRef builder = ctx->builder; 58bf215546Sopenharmony_ci LLVMValueRef all_w_negative = ctx->i1true; 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_ci w->w_reflection = ctx->i1false; 61bf215546Sopenharmony_ci w->any_w_negative = ctx->i1false; 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_ci for (unsigned i = 0; i < num_vertices; i++) { 64bf215546Sopenharmony_ci LLVMValueRef neg_w; 65bf215546Sopenharmony_ci 66bf215546Sopenharmony_ci neg_w = LLVMBuildFCmp(builder, LLVMRealOLT, pos[i][3], ctx->f32_0, ""); 67bf215546Sopenharmony_ci /* If neg_w is true, negate w_reflection. */ 68bf215546Sopenharmony_ci w->w_reflection = LLVMBuildXor(builder, w->w_reflection, neg_w, ""); 69bf215546Sopenharmony_ci w->any_w_negative = LLVMBuildOr(builder, w->any_w_negative, neg_w, ""); 70bf215546Sopenharmony_ci all_w_negative = LLVMBuildAnd(builder, all_w_negative, neg_w, ""); 71bf215546Sopenharmony_ci } 72bf215546Sopenharmony_ci w->w_accepted = LLVMBuildNot(builder, all_w_negative, ""); 73bf215546Sopenharmony_ci} 74bf215546Sopenharmony_ci 75bf215546Sopenharmony_ci/* Perform front/back face culling and return true if the primitive is accepted. */ 76bf215546Sopenharmony_cistatic LLVMValueRef ac_cull_face(struct ac_llvm_context *ctx, LLVMValueRef pos[3][4], 77bf215546Sopenharmony_ci struct ac_position_w_info *w, bool cull_front, bool cull_back, 78bf215546Sopenharmony_ci bool cull_zero_area) 79bf215546Sopenharmony_ci{ 80bf215546Sopenharmony_ci LLVMBuilderRef builder = ctx->builder; 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci if (cull_front && cull_back) 83bf215546Sopenharmony_ci return ctx->i1false; 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_ci if (!cull_front && !cull_back && !cull_zero_area) 86bf215546Sopenharmony_ci return ctx->i1true; 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_ci /* Front/back face culling. Also if the determinant == 0, the triangle 89bf215546Sopenharmony_ci * area is 0. 90bf215546Sopenharmony_ci */ 91bf215546Sopenharmony_ci LLVMValueRef det_t0 = LLVMBuildFSub(builder, pos[2][0], pos[0][0], ""); 92bf215546Sopenharmony_ci LLVMValueRef det_t1 = LLVMBuildFSub(builder, pos[1][1], pos[0][1], ""); 93bf215546Sopenharmony_ci LLVMValueRef det_t2 = LLVMBuildFSub(builder, pos[0][0], pos[1][0], ""); 94bf215546Sopenharmony_ci LLVMValueRef det_t3 = LLVMBuildFSub(builder, pos[0][1], pos[2][1], ""); 95bf215546Sopenharmony_ci /* t0 * t1 - t2 * t3 = t2 * -t3 + t0 * t1 = fma(t2, -t3, t0 * t1) */ 96bf215546Sopenharmony_ci LLVMValueRef det = ac_build_fmad(ctx, det_t2, LLVMBuildFNeg(builder, det_t3, ""), 97bf215546Sopenharmony_ci LLVMBuildFMul(builder, det_t0, det_t1, "")); 98bf215546Sopenharmony_ci 99bf215546Sopenharmony_ci /* Negative W negates the determinant. */ 100bf215546Sopenharmony_ci det = LLVMBuildSelect(builder, w->w_reflection, LLVMBuildFNeg(builder, det, ""), det, ""); 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_ci LLVMValueRef accepted = NULL; 103bf215546Sopenharmony_ci if (cull_front) { 104bf215546Sopenharmony_ci LLVMRealPredicate cond = cull_zero_area ? LLVMRealOGT : LLVMRealOGE; 105bf215546Sopenharmony_ci accepted = LLVMBuildFCmp(builder, cond, det, ctx->f32_0, ""); 106bf215546Sopenharmony_ci } else if (cull_back) { 107bf215546Sopenharmony_ci LLVMRealPredicate cond = cull_zero_area ? LLVMRealOLT : LLVMRealOLE; 108bf215546Sopenharmony_ci accepted = LLVMBuildFCmp(builder, cond, det, ctx->f32_0, ""); 109bf215546Sopenharmony_ci } else if (cull_zero_area) { 110bf215546Sopenharmony_ci accepted = LLVMBuildFCmp(builder, LLVMRealONE, det, ctx->f32_0, ""); 111bf215546Sopenharmony_ci } 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci if (accepted) { 114bf215546Sopenharmony_ci /* Don't reject NaN and +/-infinity, these are tricky. 115bf215546Sopenharmony_ci * Just trust fixed-function HW to handle these cases correctly. 116bf215546Sopenharmony_ci */ 117bf215546Sopenharmony_ci accepted = LLVMBuildOr(builder, accepted, ac_build_is_inf_or_nan(ctx, det), ""); 118bf215546Sopenharmony_ci } 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci return accepted; 121bf215546Sopenharmony_ci} 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_cistatic void rotate_45degrees(struct ac_llvm_context *ctx, LLVMValueRef v[2]) 124bf215546Sopenharmony_ci{ 125bf215546Sopenharmony_ci /* sin(45) == cos(45) */ 126bf215546Sopenharmony_ci LLVMValueRef sincos45 = LLVMConstReal(ctx->f32, 0.707106781); 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_ci /* x2 = x*cos45 - y*sin45 = x*sincos45 - y*sincos45 129bf215546Sopenharmony_ci * y2 = x*sin45 + y*cos45 = x*sincos45 + y*sincos45 130bf215546Sopenharmony_ci */ 131bf215546Sopenharmony_ci LLVMValueRef first = LLVMBuildFMul(ctx->builder, v[0], sincos45, ""); 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci /* Doing 2x ffma while duplicating the multiplication is 33% faster than fmul+fadd+fadd. */ 134bf215546Sopenharmony_ci LLVMValueRef result[2] = { 135bf215546Sopenharmony_ci ac_build_fmad(ctx, LLVMBuildFNeg(ctx->builder, v[1], ""), sincos45, first), 136bf215546Sopenharmony_ci ac_build_fmad(ctx, v[1], sincos45, first), 137bf215546Sopenharmony_ci }; 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci memcpy(v, result, sizeof(result)); 140bf215546Sopenharmony_ci} 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_ci/* Perform view culling and small primitive elimination and return true 143bf215546Sopenharmony_ci * if the primitive is accepted and initially_accepted == true. */ 144bf215546Sopenharmony_cistatic void cull_bbox(struct ac_llvm_context *ctx, LLVMValueRef pos[3][4], 145bf215546Sopenharmony_ci LLVMValueRef initially_accepted, struct ac_position_w_info *w, 146bf215546Sopenharmony_ci LLVMValueRef vp_scale[2], LLVMValueRef vp_translate[2], 147bf215546Sopenharmony_ci LLVMValueRef small_prim_precision, 148bf215546Sopenharmony_ci LLVMValueRef clip_half_line_width[2], 149bf215546Sopenharmony_ci struct ac_cull_options *options, 150bf215546Sopenharmony_ci ac_cull_accept_func accept_func, void *userdata) 151bf215546Sopenharmony_ci{ 152bf215546Sopenharmony_ci LLVMBuilderRef builder = ctx->builder; 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci if (!options->cull_view_xy && !options->cull_view_near_z && !options->cull_view_far_z && 155bf215546Sopenharmony_ci !options->cull_small_prims) { 156bf215546Sopenharmony_ci if (accept_func) 157bf215546Sopenharmony_ci accept_func(ctx, initially_accepted, userdata); 158bf215546Sopenharmony_ci return; 159bf215546Sopenharmony_ci } 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci ac_build_ifcc(ctx, initially_accepted, 10000000); 162bf215546Sopenharmony_ci { 163bf215546Sopenharmony_ci LLVMValueRef bbox_min[3], bbox_max[3]; 164bf215546Sopenharmony_ci LLVMValueRef accepted = ctx->i1true; 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci /* Compute the primitive bounding box for easy culling. */ 167bf215546Sopenharmony_ci for (unsigned chan = 0; chan < (options->cull_view_near_z || 168bf215546Sopenharmony_ci options->cull_view_far_z ? 3 : 2); chan++) { 169bf215546Sopenharmony_ci assert(options->num_vertices >= 2); 170bf215546Sopenharmony_ci bbox_min[chan] = ac_build_fmin(ctx, pos[0][chan], pos[1][chan]); 171bf215546Sopenharmony_ci bbox_max[chan] = ac_build_fmax(ctx, pos[0][chan], pos[1][chan]); 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci if (options->num_vertices == 3) { 174bf215546Sopenharmony_ci bbox_min[chan] = ac_build_fmin(ctx, bbox_min[chan], pos[2][chan]); 175bf215546Sopenharmony_ci bbox_max[chan] = ac_build_fmax(ctx, bbox_max[chan], pos[2][chan]); 176bf215546Sopenharmony_ci } 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci if (clip_half_line_width[chan]) { 179bf215546Sopenharmony_ci bbox_min[chan] = LLVMBuildFSub(builder, bbox_min[chan], clip_half_line_width[chan], ""); 180bf215546Sopenharmony_ci bbox_max[chan] = LLVMBuildFAdd(builder, bbox_max[chan], clip_half_line_width[chan], ""); 181bf215546Sopenharmony_ci } 182bf215546Sopenharmony_ci } 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci /* View culling. */ 185bf215546Sopenharmony_ci if (options->cull_view_xy || options->cull_view_near_z || options->cull_view_far_z) { 186bf215546Sopenharmony_ci for (unsigned chan = 0; chan < 3; chan++) { 187bf215546Sopenharmony_ci LLVMValueRef visible; 188bf215546Sopenharmony_ci 189bf215546Sopenharmony_ci if ((options->cull_view_xy && chan <= 1) || (options->cull_view_near_z && chan == 2)) { 190bf215546Sopenharmony_ci float t = chan == 2 && options->use_halfz_clip_space ? 0 : -1; 191bf215546Sopenharmony_ci visible = LLVMBuildFCmp(builder, LLVMRealOGE, bbox_max[chan], 192bf215546Sopenharmony_ci LLVMConstReal(ctx->f32, t), ""); 193bf215546Sopenharmony_ci accepted = LLVMBuildAnd(builder, accepted, visible, ""); 194bf215546Sopenharmony_ci } 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci if ((options->cull_view_xy && chan <= 1) || (options->cull_view_far_z && chan == 2)) { 197bf215546Sopenharmony_ci visible = LLVMBuildFCmp(builder, LLVMRealOLE, bbox_min[chan], ctx->f32_1, ""); 198bf215546Sopenharmony_ci accepted = LLVMBuildAnd(builder, accepted, visible, ""); 199bf215546Sopenharmony_ci } 200bf215546Sopenharmony_ci } 201bf215546Sopenharmony_ci } 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_ci /* Small primitive culling - triangles. */ 204bf215546Sopenharmony_ci if (options->cull_small_prims && options->num_vertices == 3) { 205bf215546Sopenharmony_ci /* Assuming a sample position at (0.5, 0.5), if we round 206bf215546Sopenharmony_ci * the bounding box min/max extents and the results of 207bf215546Sopenharmony_ci * the rounding are equal in either the X or Y direction, 208bf215546Sopenharmony_ci * the bounding box does not intersect the sample. 209bf215546Sopenharmony_ci * 210bf215546Sopenharmony_ci * See these GDC slides for pictures: 211bf215546Sopenharmony_ci * https://frostbite-wp-prd.s3.amazonaws.com/wp-content/uploads/2016/03/29204330/GDC_2016_Compute.pdf 212bf215546Sopenharmony_ci */ 213bf215546Sopenharmony_ci LLVMValueRef min, max, not_equal[2], visible; 214bf215546Sopenharmony_ci 215bf215546Sopenharmony_ci for (unsigned chan = 0; chan < 2; chan++) { 216bf215546Sopenharmony_ci /* Convert the position to screen-space coordinates. */ 217bf215546Sopenharmony_ci min = ac_build_fmad(ctx, bbox_min[chan], vp_scale[chan], vp_translate[chan]); 218bf215546Sopenharmony_ci max = ac_build_fmad(ctx, bbox_max[chan], vp_scale[chan], vp_translate[chan]); 219bf215546Sopenharmony_ci /* Scale the bounding box according to the precision of 220bf215546Sopenharmony_ci * the rasterizer and the number of MSAA samples. */ 221bf215546Sopenharmony_ci min = LLVMBuildFSub(builder, min, small_prim_precision, ""); 222bf215546Sopenharmony_ci max = LLVMBuildFAdd(builder, max, small_prim_precision, ""); 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_ci /* Determine if the bbox intersects the sample point. 225bf215546Sopenharmony_ci * It also works for MSAA, but vp_scale, vp_translate, 226bf215546Sopenharmony_ci * and small_prim_precision are computed differently. 227bf215546Sopenharmony_ci */ 228bf215546Sopenharmony_ci min = ac_build_round(ctx, min); 229bf215546Sopenharmony_ci max = ac_build_round(ctx, max); 230bf215546Sopenharmony_ci not_equal[chan] = LLVMBuildFCmp(builder, LLVMRealONE, min, max, ""); 231bf215546Sopenharmony_ci } 232bf215546Sopenharmony_ci visible = LLVMBuildAnd(builder, not_equal[0], not_equal[1], ""); 233bf215546Sopenharmony_ci accepted = LLVMBuildAnd(builder, accepted, visible, ""); 234bf215546Sopenharmony_ci } 235bf215546Sopenharmony_ci 236bf215546Sopenharmony_ci /* Small primitive culling - lines. */ 237bf215546Sopenharmony_ci if (options->cull_small_prims && options->num_vertices == 2) { 238bf215546Sopenharmony_ci /* This only works with lines without perpendicular end caps (lines with perpendicular 239bf215546Sopenharmony_ci * end caps are rasterized as quads and thus can't be culled as small prims in 99% of 240bf215546Sopenharmony_ci * cases because line_width >= 1). 241bf215546Sopenharmony_ci * 242bf215546Sopenharmony_ci * This takes advantage of the diamont exit rule, which says that every pixel 243bf215546Sopenharmony_ci * has a diamond inside it touching the pixel boundary and only if a line exits 244bf215546Sopenharmony_ci * the diamond, that pixel is filled. If a line enters the diamond or stays 245bf215546Sopenharmony_ci * outside the diamond, the pixel isn't filled. 246bf215546Sopenharmony_ci * 247bf215546Sopenharmony_ci * This algorithm is a little simpler than that. The space outside all diamonds also 248bf215546Sopenharmony_ci * has the same diamond shape, which we'll call corner diamonds. 249bf215546Sopenharmony_ci * 250bf215546Sopenharmony_ci * The idea is to cull all lines that are entirely inside a diamond, including 251bf215546Sopenharmony_ci * corner diamonds. If a line is entirely inside a diamond, it can be culled because 252bf215546Sopenharmony_ci * it doesn't exit it. If a line is entirely inside a corner diamond, it can be culled 253bf215546Sopenharmony_ci * because it doesn't enter any diamond and thus can't exit any diamond. 254bf215546Sopenharmony_ci * 255bf215546Sopenharmony_ci * The viewport is rotated by 45 degress to turn diamonds into squares, and a bounding 256bf215546Sopenharmony_ci * box test is used to determine whether a line is entirely inside any square (diamond). 257bf215546Sopenharmony_ci * 258bf215546Sopenharmony_ci * The line width doesn't matter. Wide lines only duplicate filled pixels in either X or 259bf215546Sopenharmony_ci * Y direction from the filled pixels. MSAA also doesn't matter. MSAA should ideally use 260bf215546Sopenharmony_ci * perpendicular end caps that enable quad rasterization for lines. Thus, this should 261bf215546Sopenharmony_ci * always use non-MSAA viewport transformation and non-MSAA small prim precision. 262bf215546Sopenharmony_ci * 263bf215546Sopenharmony_ci * A good test is piglit/lineloop because it draws 10k subpixel lines in a circle. 264bf215546Sopenharmony_ci * It should contain no holes if this matches hw behavior. 265bf215546Sopenharmony_ci */ 266bf215546Sopenharmony_ci LLVMValueRef v0[2], v1[2]; 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ci /* Get vertex positions in pixels. */ 269bf215546Sopenharmony_ci for (unsigned chan = 0; chan < 2; chan++) { 270bf215546Sopenharmony_ci v0[chan] = ac_build_fmad(ctx, pos[0][chan], vp_scale[chan], vp_translate[chan]); 271bf215546Sopenharmony_ci v1[chan] = ac_build_fmad(ctx, pos[1][chan], vp_scale[chan], vp_translate[chan]); 272bf215546Sopenharmony_ci } 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci /* Rotate the viewport by 45 degress, so that diamonds become squares. */ 275bf215546Sopenharmony_ci rotate_45degrees(ctx, v0); 276bf215546Sopenharmony_ci rotate_45degrees(ctx, v1); 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci LLVMValueRef not_equal[2]; 279bf215546Sopenharmony_ci 280bf215546Sopenharmony_ci for (unsigned chan = 0; chan < 2; chan++) { 281bf215546Sopenharmony_ci /* The width of each square is sqrt(0.5), so scale it to 1 because we want 282bf215546Sopenharmony_ci * round() to give us the position of the closest center of a square (diamond). 283bf215546Sopenharmony_ci */ 284bf215546Sopenharmony_ci v0[chan] = LLVMBuildFMul(builder, v0[chan], LLVMConstReal(ctx->f32, 1.414213562), ""); 285bf215546Sopenharmony_ci v1[chan] = LLVMBuildFMul(builder, v1[chan], LLVMConstReal(ctx->f32, 1.414213562), ""); 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_ci /* Compute the bounding box around both vertices. We do this because we must 288bf215546Sopenharmony_ci * enlarge the line area by the precision of the rasterizer. 289bf215546Sopenharmony_ci */ 290bf215546Sopenharmony_ci LLVMValueRef min = ac_build_fmin(ctx, v0[chan], v1[chan]); 291bf215546Sopenharmony_ci LLVMValueRef max = ac_build_fmax(ctx, v0[chan], v1[chan]); 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_ci /* Enlarge the bounding box by the precision of the rasterizer. */ 294bf215546Sopenharmony_ci min = LLVMBuildFSub(builder, min, small_prim_precision, ""); 295bf215546Sopenharmony_ci max = LLVMBuildFAdd(builder, max, small_prim_precision, ""); 296bf215546Sopenharmony_ci 297bf215546Sopenharmony_ci /* Round the bounding box corners. If both rounded corners are equal, 298bf215546Sopenharmony_ci * the bounding box is entirely inside a square (diamond). 299bf215546Sopenharmony_ci */ 300bf215546Sopenharmony_ci min = ac_build_round(ctx, min); 301bf215546Sopenharmony_ci max = ac_build_round(ctx, max); 302bf215546Sopenharmony_ci not_equal[chan] = LLVMBuildFCmp(builder, LLVMRealONE, min, max, ""); 303bf215546Sopenharmony_ci } 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_ci accepted = LLVMBuildAnd(builder, accepted, 306bf215546Sopenharmony_ci LLVMBuildOr(builder, not_equal[0], not_equal[1], ""), ""); 307bf215546Sopenharmony_ci } 308bf215546Sopenharmony_ci 309bf215546Sopenharmony_ci /* Disregard the bounding box culling if any W is negative because the code 310bf215546Sopenharmony_ci * doesn't work with that. 311bf215546Sopenharmony_ci */ 312bf215546Sopenharmony_ci accepted = LLVMBuildOr(builder, accepted, w->any_w_negative, ""); 313bf215546Sopenharmony_ci 314bf215546Sopenharmony_ci if (accept_func) 315bf215546Sopenharmony_ci accept_func(ctx, accepted, userdata); 316bf215546Sopenharmony_ci } 317bf215546Sopenharmony_ci ac_build_endif(ctx, 10000000); 318bf215546Sopenharmony_ci} 319bf215546Sopenharmony_ci 320bf215546Sopenharmony_ci/** 321bf215546Sopenharmony_ci * Return i1 true if the primitive is accepted (not culled). 322bf215546Sopenharmony_ci * 323bf215546Sopenharmony_ci * \param pos Vertex positions 3x vec4 324bf215546Sopenharmony_ci * \param initially_accepted AND'ed with the result. Some computations can be 325bf215546Sopenharmony_ci * skipped if this is false. 326bf215546Sopenharmony_ci * \param vp_scale Viewport scale XY. 327bf215546Sopenharmony_ci * For MSAA, multiply them by the number of samples. 328bf215546Sopenharmony_ci * \param vp_translate Viewport translation XY. 329bf215546Sopenharmony_ci * For MSAA, multiply them by the number of samples. 330bf215546Sopenharmony_ci * \param small_prim_precision Precision of small primitive culling. This should 331bf215546Sopenharmony_ci * be the same as or greater than the precision of 332bf215546Sopenharmony_ci * the rasterizer. Set to num_samples / 2^subpixel_bits. 333bf215546Sopenharmony_ci * subpixel_bits are defined by the quantization mode. 334bf215546Sopenharmony_ci * \param options See ac_cull_options. 335bf215546Sopenharmony_ci * \param accept_func Callback invoked in the inner-most branch where the primitive is accepted. 336bf215546Sopenharmony_ci */ 337bf215546Sopenharmony_civoid ac_cull_primitive(struct ac_llvm_context *ctx, LLVMValueRef pos[3][4], 338bf215546Sopenharmony_ci LLVMValueRef initially_accepted, LLVMValueRef vp_scale[2], 339bf215546Sopenharmony_ci LLVMValueRef vp_translate[2], LLVMValueRef small_prim_precision, 340bf215546Sopenharmony_ci LLVMValueRef clip_half_line_width[2], struct ac_cull_options *options, 341bf215546Sopenharmony_ci ac_cull_accept_func accept_func, void *userdata) 342bf215546Sopenharmony_ci{ 343bf215546Sopenharmony_ci struct ac_position_w_info w; 344bf215546Sopenharmony_ci ac_analyze_position_w(ctx, pos, &w, options->num_vertices); 345bf215546Sopenharmony_ci 346bf215546Sopenharmony_ci /* W culling. */ 347bf215546Sopenharmony_ci LLVMValueRef accepted = options->cull_w ? w.w_accepted : ctx->i1true; 348bf215546Sopenharmony_ci accepted = LLVMBuildAnd(ctx->builder, accepted, initially_accepted, ""); 349bf215546Sopenharmony_ci 350bf215546Sopenharmony_ci /* Face culling. */ 351bf215546Sopenharmony_ci accepted = LLVMBuildAnd( 352bf215546Sopenharmony_ci ctx->builder, accepted, 353bf215546Sopenharmony_ci ac_cull_face(ctx, pos, &w, options->cull_front, options->cull_back, options->cull_zero_area), 354bf215546Sopenharmony_ci ""); 355bf215546Sopenharmony_ci 356bf215546Sopenharmony_ci /* View culling and small primitive elimination. */ 357bf215546Sopenharmony_ci cull_bbox(ctx, pos, accepted, &w, vp_scale, vp_translate, small_prim_precision, 358bf215546Sopenharmony_ci clip_half_line_width, options, accept_func, userdata); 359bf215546Sopenharmony_ci} 360