message: clusterizer: Instead of assuming worst-case SNORM error, measure it
  We now measure the maximum error from axis quantization and round the
  cutoff up based on that; this increases the SNORM culling efficiency by
  ~1% relative.
diff: @@ -303,11 +303,16 @@ meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t
  bounds.cone_axis_s8[0] = char(meshopt_quantizeSnorm(bounds.cone_axis[0], 8));
  bounds.cone_axis_s8[1] = char(meshopt_quantizeSnorm(bounds.cone_axis[1], 8));
  bounds.cone_axis_s8[2] = char(meshopt_quantizeSnorm(bounds.cone_axis[2], 8));
  - bounds.cone_cutoff_s8 = char(meshopt_quantizeSnorm(bounds.cone_cutoff, 8));
  - // for the test to be conservative, we need to adjust the cutoff
  - // each axis component has up to 0.5/127 error, so the dot product can accumulate 1.5/127; the cutoff can also get rounded down for an extra 0.5/127 error
  - bounds.cone_cutoff_s8 = (bounds.cone_cutoff_s8 < 125) ? bounds.cone_cutoff_s8 + 2 : 127;
  + // for the 8-bit test to be conservative, we need to adjust the cutoff by measuring the max. error
  + float cone_axis_s8_e0 = fabsf(bounds.cone_axis_s8[0] / 127.f - bounds.cone_axis[0]);
  + float cone_axis_s8_e1 = fabsf(bounds.cone_axis_s8[1] / 127.f - bounds.cone_axis[1]);
  + float cone_axis_s8_e2 = fabsf(bounds.cone_axis_s8[2] / 127.f - bounds.cone_axis[2]);
  +
  + // note that we need to round this up instead of rounding to nearest, hence +1
  + int cone_cutoff_s8 = int(127 * (bounds.cone_cutoff + cone_axis_s8_e0 + cone_axis_s8_e1 + cone_axis_s8_e2) + 1);
  +
  + bounds.cone_cutoff_s8 = (cone_cutoff_s8 > 127) ? 127 : char(cone_cutoff_s8);
  return bounds;
  }
  