@deck.gl/extensions 9.4.0-alpha.2 → 9.4.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/dist.dev.js CHANGED
@@ -13,7 +13,11 @@ var __exports__ = (() => {
13
13
  var __getProtoOf = Object.getPrototypeOf;
14
14
  var __hasOwnProp = Object.prototype.hasOwnProperty;
15
15
  var __commonJS = (cb, mod) => function __require() {
16
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
16
+ try {
17
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
18
+ } catch (e) {
19
+ throw mod = 0, e;
20
+ }
17
21
  };
18
22
  var __export = (target, all) => {
19
23
  for (var name in all)
@@ -918,8 +922,7 @@ void main() {
918
922
  */
919
923
  _updateCategoryBitMask(params, extension) {
920
924
  const { categorySize } = extension.opts;
921
- if (!categorySize)
922
- return;
925
+ if (!categorySize) return;
923
926
  const { filterCategories } = this.props;
924
927
  const categoryBitMask = new Uint32Array([0, 0, 0, 0]);
925
928
  const categoryFilters = categorySize === 1 ? [filterCategories] : filterCategories;
@@ -1417,7 +1420,7 @@ void main() {
1417
1420
  var sqrDist = squaredDistance;
1418
1421
  var len = length;
1419
1422
  var sqrLen = squaredLength;
1420
- var forEach = function() {
1423
+ var forEach = (function() {
1421
1424
  const vec = create();
1422
1425
  return function(a, stride, offset, count, fn, arg) {
1423
1426
  let i;
@@ -1444,7 +1447,7 @@ void main() {
1444
1447
  }
1445
1448
  return a;
1446
1449
  };
1447
- }();
1450
+ })();
1448
1451
 
1449
1452
  // ../../node_modules/@luma.gl/shadertools/dist/modules/math/fp64/fp64-utils.js
1450
1453
  function fp64ify(a, out = [], startIndex = 0) {
@@ -1673,6 +1676,462 @@ vec2 sqrt_fp64(vec2 a) {
1673
1676
  `
1674
1677
  );
1675
1678
 
1679
+ // ../../node_modules/@luma.gl/shadertools/dist/modules/math/fp64/fp64-arithmetic-wgsl-integer.js
1680
+ var fp64arithmeticWGSLInteger = (
1681
+ /* wgsl */
1682
+ `struct Fp64F32Bits {
1683
+ sign: u32,
1684
+ baseExponent: i32,
1685
+ significand: u32,
1686
+ isZero: bool,
1687
+ isInf: bool,
1688
+ isNan: bool,
1689
+ };
1690
+
1691
+ // Decode an f32 as (-1)^sign * significand * 2^baseExponent.
1692
+ fn fp64_decode_f32_bits(bits: u32) -> Fp64F32Bits {
1693
+ let sign = bits >> 31u;
1694
+ let exponentBits = (bits >> 23u) & 0xffu;
1695
+ let fraction = bits & 0x7fffffu;
1696
+
1697
+ if (exponentBits == 0xffu) {
1698
+ return Fp64F32Bits(sign, 0, 0u, false, fraction == 0u, fraction != 0u);
1699
+ }
1700
+ if (exponentBits == 0u) {
1701
+ return Fp64F32Bits(sign, -149, fraction, fraction == 0u, false, false);
1702
+ }
1703
+ return Fp64F32Bits(sign, i32(exponentBits) - 150, 0x800000u | fraction, false, false, false);
1704
+ }
1705
+
1706
+ fn fp64_f32_magnitude_compare(aBits: u32, bBits: u32) -> i32 {
1707
+ let aMagnitude = aBits & 0x7fffffffu;
1708
+ let bMagnitude = bBits & 0x7fffffffu;
1709
+ if (aMagnitude == bMagnitude) {
1710
+ return 0;
1711
+ }
1712
+ return select(-1, 1, aMagnitude > bMagnitude);
1713
+ }
1714
+
1715
+ fn fp64_make_residual_f32_bits(
1716
+ exactSign: u32,
1717
+ exactMagnitude: vec2u,
1718
+ exactBaseExponent: i32,
1719
+ highBits: u32
1720
+ ) -> u32 {
1721
+ if (fp64_u64_is_zero(exactMagnitude)) {
1722
+ return 0u;
1723
+ }
1724
+
1725
+ let high = fp64_decode_f32_bits(highBits);
1726
+ if (high.isInf || high.isNan) {
1727
+ return exactSign << 31u;
1728
+ }
1729
+ if (high.isZero) {
1730
+ return fp64_make_f32_bits_from_u64(exactSign, exactMagnitude, exactBaseExponent);
1731
+ }
1732
+
1733
+ let commonBaseExponent = min(exactBaseExponent, high.baseExponent);
1734
+ let exactShift = exactBaseExponent - commonBaseExponent;
1735
+ let highShift = high.baseExponent - commonBaseExponent;
1736
+
1737
+ // A normal two-sum/two-product residual never needs a shift this large.
1738
+ // This guard gives deterministic underflow behavior outside that contract.
1739
+ if (exactShift >= 64 || highShift >= 64) {
1740
+ return exactSign << 31u;
1741
+ }
1742
+
1743
+ let exactAligned = fp64_u64_shift_left(exactMagnitude, u32(exactShift));
1744
+ let highAligned = fp64_u64_shift_left(vec2u(0u, high.significand), u32(highShift));
1745
+ let comparison = fp64_u64_compare(exactAligned, highAligned);
1746
+ if (comparison == 0) {
1747
+ return 0u;
1748
+ }
1749
+
1750
+ var residualSign = exactSign;
1751
+ var residualMagnitude: vec2u;
1752
+ if (comparison > 0) {
1753
+ residualMagnitude = fp64_u64_sub(exactAligned, highAligned);
1754
+ } else {
1755
+ residualSign = exactSign ^ 1u;
1756
+ residualMagnitude = fp64_u64_sub(highAligned, exactAligned);
1757
+ }
1758
+ return fp64_make_f32_bits_from_u64(
1759
+ residualSign,
1760
+ residualMagnitude,
1761
+ commonBaseExponent
1762
+ );
1763
+ }
1764
+
1765
+ fn fp64_split_accumulator_bits(
1766
+ sign: u32,
1767
+ magnitude: vec2u,
1768
+ baseExponent: i32
1769
+ ) -> vec2u {
1770
+ let highBits = fp64_make_f32_bits_from_u64(sign, magnitude, baseExponent);
1771
+ let lowBits = fp64_make_residual_f32_bits(sign, magnitude, baseExponent, highBits);
1772
+ return vec2u(highBits, lowBits);
1773
+ }
1774
+
1775
+ fn fp64_two_sum_integer_bits(aBits: u32, bBits: u32) -> vec2u {
1776
+ let a = fp64_decode_f32_bits(aBits);
1777
+ let b = fp64_decode_f32_bits(bBits);
1778
+
1779
+ if (a.isNan || b.isNan) {
1780
+ return vec2u(0x7fc00000u, 0u);
1781
+ }
1782
+ if (a.isInf || b.isInf) {
1783
+ if (a.isInf && b.isInf && a.sign != b.sign) {
1784
+ return vec2u(0x7fc00000u, 0u);
1785
+ }
1786
+ return select(vec2u(bBits, 0u), vec2u(aBits, 0u), a.isInf);
1787
+ }
1788
+ if (a.isZero && b.isZero) {
1789
+ return vec2u((a.sign & b.sign) << 31u, 0u);
1790
+ }
1791
+ if (a.isZero) {
1792
+ return vec2u(bBits, 0u);
1793
+ }
1794
+ if (b.isZero) {
1795
+ return vec2u(aBits, 0u);
1796
+ }
1797
+
1798
+ let exponentDifference = select(
1799
+ b.baseExponent - a.baseExponent,
1800
+ a.baseExponent - b.baseExponent,
1801
+ a.baseExponent >= b.baseExponent
1802
+ );
1803
+
1804
+ // Beyond half an ulp, rounding cannot change the larger operand. Returning
1805
+ // the smaller operand intact also avoids an unbounded integer alignment.
1806
+ // At a power-of-two boundary the spacing below the larger operand is half
1807
+ // the spacing above it, so an opposite-sign gap-25 operand can still change
1808
+ // the rounded high limb. Gap 26 is the first universally safe early-out.
1809
+ if (exponentDifference > 25) {
1810
+ if (fp64_f32_magnitude_compare(aBits, bBits) >= 0) {
1811
+ return vec2u(aBits, bBits);
1812
+ }
1813
+ return vec2u(bBits, aBits);
1814
+ }
1815
+
1816
+ let commonBaseExponent = min(a.baseExponent, b.baseExponent);
1817
+ let aMagnitude = fp64_u64_shift_left(
1818
+ vec2u(0u, a.significand),
1819
+ u32(a.baseExponent - commonBaseExponent)
1820
+ );
1821
+ let bMagnitude = fp64_u64_shift_left(
1822
+ vec2u(0u, b.significand),
1823
+ u32(b.baseExponent - commonBaseExponent)
1824
+ );
1825
+
1826
+ var resultSign = a.sign;
1827
+ var resultMagnitude: vec2u;
1828
+ if (a.sign == b.sign) {
1829
+ resultMagnitude = fp64_u64_add(aMagnitude, bMagnitude);
1830
+ } else {
1831
+ let comparison = fp64_u64_compare(aMagnitude, bMagnitude);
1832
+ if (comparison == 0) {
1833
+ return vec2u(0u, 0u);
1834
+ }
1835
+ if (comparison > 0) {
1836
+ resultMagnitude = fp64_u64_sub(aMagnitude, bMagnitude);
1837
+ } else {
1838
+ resultSign = b.sign;
1839
+ resultMagnitude = fp64_u64_sub(bMagnitude, aMagnitude);
1840
+ }
1841
+ }
1842
+
1843
+ return fp64_split_accumulator_bits(resultSign, resultMagnitude, commonBaseExponent);
1844
+ }
1845
+
1846
+ fn fp64_two_sum_integer(a: f32, b: f32) -> vec2f {
1847
+ let resultBits = fp64_two_sum_integer_bits(bitcast<u32>(a), bitcast<u32>(b));
1848
+ return vec2f(bitcast<f32>(resultBits.x), bitcast<f32>(resultBits.y));
1849
+ }
1850
+
1851
+ fn fp64_multiply_significands(a: u32, b: u32) -> vec2u {
1852
+ let aLow = a & 0xffffu;
1853
+ let aHigh = a >> 16u;
1854
+ let bLow = b & 0xffffu;
1855
+ let bHigh = b >> 16u;
1856
+ let lowProduct = aLow * bLow;
1857
+ let crossProduct = aLow * bHigh + aHigh * bLow;
1858
+ let highProduct = aHigh * bHigh;
1859
+
1860
+ var result = vec2u(0u, lowProduct);
1861
+ result = fp64_u64_add(
1862
+ result,
1863
+ fp64_u64_shift_left(vec2u(0u, crossProduct), 16u)
1864
+ );
1865
+ result = fp64_u64_add(result, vec2u(highProduct, 0u));
1866
+ return result;
1867
+ }
1868
+
1869
+ fn fp64_two_prod_integer_bits(aBits: u32, bBits: u32) -> vec2u {
1870
+ let a = fp64_decode_f32_bits(aBits);
1871
+ let b = fp64_decode_f32_bits(bBits);
1872
+ let resultSign = a.sign ^ b.sign;
1873
+
1874
+ if (a.isNan || b.isNan || ((a.isZero || b.isZero) && (a.isInf || b.isInf))) {
1875
+ return vec2u(0x7fc00000u, 0u);
1876
+ }
1877
+ if (a.isInf || b.isInf) {
1878
+ return vec2u((resultSign << 31u) | 0x7f800000u, resultSign << 31u);
1879
+ }
1880
+ if (a.isZero || b.isZero) {
1881
+ return vec2u(resultSign << 31u, resultSign << 31u);
1882
+ }
1883
+
1884
+ let magnitude = fp64_multiply_significands(a.significand, b.significand);
1885
+ return fp64_split_accumulator_bits(
1886
+ resultSign,
1887
+ magnitude,
1888
+ a.baseExponent + b.baseExponent
1889
+ );
1890
+ }
1891
+
1892
+ fn fp64_two_prod_integer(a: f32, b: f32) -> vec2f {
1893
+ let resultBits = fp64_two_prod_integer_bits(bitcast<u32>(a), bitcast<u32>(b));
1894
+ return vec2f(bitcast<f32>(resultBits.x), bitcast<f32>(resultBits.y));
1895
+ }
1896
+
1897
+ fn fp64_round_add_integer(a: f32, b: f32) -> f32 {
1898
+ return fp64_two_sum_integer(a, b).x;
1899
+ }
1900
+
1901
+ fn fp64_round_mul_integer(a: f32, b: f32) -> f32 {
1902
+ return fp64_two_prod_integer(a, b).x;
1903
+ }
1904
+
1905
+ #ifndef LUMA_FP64_PREDICATE_ONLY
1906
+ fn fp64_f32_finite_exponent(value: Fp64F32Bits) -> i32 {
1907
+ let mostSignificantBit = 31u - countLeadingZeros(value.significand);
1908
+ return value.baseExponent + i32(mostSignificantBit);
1909
+ }
1910
+
1911
+ fn fp64_scale_f32_integer(value: f32, exponent: i32) -> f32 {
1912
+ let decoded = fp64_decode_f32_bits(bitcast<u32>(value));
1913
+ if (decoded.isZero || decoded.isInf || decoded.isNan) {
1914
+ return value;
1915
+ }
1916
+ let resultBits = fp64_make_f32_bits_from_u64(
1917
+ decoded.sign,
1918
+ vec2u(0u, decoded.significand),
1919
+ decoded.baseExponent + exponent
1920
+ );
1921
+ return bitcast<f32>(resultBits);
1922
+ }
1923
+
1924
+ // Divide normalized significands so the hardware operation cannot overflow,
1925
+ // underflow, or flush a subnormal result. Reapply the exponent with integer
1926
+ // packing, which also produces subnormal correction limbs without relying on
1927
+ // floating-point arithmetic to preserve them.
1928
+ fn fp64_divide_f32_integer(aValue: f32, bValue: f32) -> f32 {
1929
+ let a = fp64_decode_f32_bits(bitcast<u32>(aValue));
1930
+ let b = fp64_decode_f32_bits(bitcast<u32>(bValue));
1931
+ if (a.isZero || b.isZero || a.isInf || b.isInf || a.isNan || b.isNan) {
1932
+ return aValue / bValue;
1933
+ }
1934
+
1935
+ let aMostSignificantBit = 31u - countLeadingZeros(a.significand);
1936
+ let bMostSignificantBit = 31u - countLeadingZeros(b.significand);
1937
+ let normalizedABits = fp64_make_f32_bits_from_u64(
1938
+ a.sign,
1939
+ vec2u(0u, a.significand),
1940
+ -i32(aMostSignificantBit)
1941
+ );
1942
+ let normalizedBBits = fp64_make_f32_bits_from_u64(
1943
+ b.sign,
1944
+ vec2u(0u, b.significand),
1945
+ -i32(bMostSignificantBit)
1946
+ );
1947
+ let normalizedQuotient = bitcast<f32>(normalizedABits) / bitcast<f32>(normalizedBBits);
1948
+ let quotient = fp64_decode_f32_bits(bitcast<u32>(normalizedQuotient));
1949
+ let exponentShift =
1950
+ a.baseExponent + i32(aMostSignificantBit) -
1951
+ b.baseExponent - i32(bMostSignificantBit);
1952
+ let quotientBits = fp64_make_f32_bits_from_u64(
1953
+ quotient.sign,
1954
+ vec2u(0u, quotient.significand),
1955
+ quotient.baseExponent + exponentShift
1956
+ );
1957
+ return bitcast<f32>(quotientBits);
1958
+ }
1959
+ #endif
1960
+
1961
+ #ifndef LUMA_FP64_PREDICATE_ONLY
1962
+ fn split(a: f32) -> vec2f {
1963
+ let aBits = bitcast<u32>(a);
1964
+ let decoded = fp64_decode_f32_bits(aBits);
1965
+ if (decoded.isZero || decoded.isInf || decoded.isNan) {
1966
+ return vec2f(a, 0.0);
1967
+ }
1968
+
1969
+ var roundedHigh = decoded.significand >> 12u;
1970
+ let remainder = decoded.significand & 0xfffu;
1971
+ if (remainder > 0x800u || (remainder == 0x800u && (roundedHigh & 1u) == 1u)) {
1972
+ roundedHigh = roundedHigh + 1u;
1973
+ }
1974
+ var highMagnitude = vec2u(0u, roundedHigh << 12u);
1975
+ var highBits = fp64_make_f32_bits_from_u64(
1976
+ decoded.sign,
1977
+ highMagnitude,
1978
+ decoded.baseExponent
1979
+ );
1980
+ // Rounding the high limb of a maximum-exponent value can overflow even
1981
+ // though the original value is finite. Truncate only in that boundary case
1982
+ // so split remains an exact finite decomposition.
1983
+ if (fp64_decode_f32_bits(highBits).isInf) {
1984
+ roundedHigh = decoded.significand >> 12u;
1985
+ highMagnitude = vec2u(0u, roundedHigh << 12u);
1986
+ highBits = fp64_make_f32_bits_from_u64(
1987
+ decoded.sign,
1988
+ highMagnitude,
1989
+ decoded.baseExponent
1990
+ );
1991
+ }
1992
+ let lowBits = fp64_make_residual_f32_bits(
1993
+ decoded.sign,
1994
+ vec2u(0u, decoded.significand),
1995
+ decoded.baseExponent,
1996
+ highBits
1997
+ );
1998
+ return vec2f(bitcast<f32>(highBits), bitcast<f32>(lowBits));
1999
+ }
2000
+
2001
+ fn split2(a: vec2f) -> vec2f {
2002
+ var result = split(a.x);
2003
+ result.y = fp64_round_add_integer(result.y, a.y);
2004
+ return result;
2005
+ }
2006
+ #endif
2007
+
2008
+ #ifndef LUMA_FP64_PREDICATE_ONLY
2009
+ fn quickTwoSum(a: f32, b: f32) -> vec2f {
2010
+ return fp64_two_sum_integer(a, b);
2011
+ }
2012
+ #endif
2013
+
2014
+ fn twoSum(a: f32, b: f32) -> vec2f {
2015
+ return fp64_two_sum_integer(a, b);
2016
+ }
2017
+
2018
+ fn twoSub(a: f32, b: f32) -> vec2f {
2019
+ let bBits = bitcast<u32>(b) ^ 0x80000000u;
2020
+ let resultBits = fp64_two_sum_integer_bits(bitcast<u32>(a), bBits);
2021
+ return vec2f(bitcast<f32>(resultBits.x), bitcast<f32>(resultBits.y));
2022
+ }
2023
+
2024
+ #ifndef LUMA_FP64_PREDICATE_ONLY
2025
+ fn twoSqr(a: f32) -> vec2f {
2026
+ return fp64_two_prod_integer(a, a);
2027
+ }
2028
+
2029
+ fn twoProd(a: f32, b: f32) -> vec2f {
2030
+ return fp64_two_prod_integer(a, b);
2031
+ }
2032
+ #endif
2033
+
2034
+ fn sum_fp64(a: vec2f, b: vec2f) -> vec2f {
2035
+ var sum = fp64_two_sum_integer(a.x, b.x);
2036
+ let lowSum = fp64_two_sum_integer(a.y, b.y);
2037
+ sum.y = fp64_round_add_integer(sum.y, lowSum.x);
2038
+ sum = fp64_two_sum_integer(sum.x, sum.y);
2039
+ sum.y = fp64_round_add_integer(sum.y, lowSum.y);
2040
+ return fp64_two_sum_integer(sum.x, sum.y);
2041
+ }
2042
+
2043
+ fn sub_fp64(a: vec2f, b: vec2f) -> vec2f {
2044
+ let negatedB = vec2f(
2045
+ bitcast<f32>(bitcast<u32>(b.x) ^ 0x80000000u),
2046
+ bitcast<f32>(bitcast<u32>(b.y) ^ 0x80000000u)
2047
+ );
2048
+ return sum_fp64(a, negatedB);
2049
+ }
2050
+
2051
+ fn mul_fp64(a: vec2f, b: vec2f) -> vec2f {
2052
+ var product = fp64_two_prod_integer(a.x, b.x);
2053
+ let crossProduct1 = fp64_round_mul_integer(a.x, b.y);
2054
+ product.y = fp64_round_add_integer(product.y, crossProduct1);
2055
+ product = fp64_two_sum_integer(product.x, product.y);
2056
+ let crossProduct2 = fp64_round_mul_integer(a.y, b.x);
2057
+ product.y = fp64_round_add_integer(product.y, crossProduct2);
2058
+ return fp64_two_sum_integer(product.x, product.y);
2059
+ }
2060
+
2061
+ #ifndef LUMA_FP64_PREDICATE_ONLY
2062
+ fn fp64_scale_fp64_integer(value: vec2f, exponent: i32) -> vec2f {
2063
+ let high = fp64_scale_f32_integer(value.x, exponent);
2064
+ let low = fp64_scale_f32_integer(value.y, exponent);
2065
+ return sum_fp64(vec2f(high, 0.0), vec2f(low, 0.0));
2066
+ }
2067
+
2068
+ fn fp64_div_fp64_normalized(a: vec2f, b: vec2f) -> vec2f {
2069
+ let quotientHigh = fp64_divide_f32_integer(a.x, b.x);
2070
+ var quotient = vec2f(quotientHigh, 0.0);
2071
+
2072
+ let remainder = sub_fp64(a, mul_fp64(b, quotient));
2073
+ let quotientLow = fp64_divide_f32_integer(remainder.x, b.x);
2074
+ quotient = sum_fp64(quotient, vec2f(quotientLow, 0.0));
2075
+
2076
+ let secondRemainder = sub_fp64(a, mul_fp64(b, quotient));
2077
+ let correction = fp64_divide_f32_integer(secondRemainder.x, b.x);
2078
+ return sum_fp64(quotient, vec2f(correction, 0.0));
2079
+ }
2080
+
2081
+ fn div_fp64(a: vec2f, b: vec2f) -> vec2f {
2082
+ let decodedA = fp64_decode_f32_bits(bitcast<u32>(a.x));
2083
+ let decodedB = fp64_decode_f32_bits(bitcast<u32>(b.x));
2084
+ if (
2085
+ decodedA.isZero || decodedB.isZero ||
2086
+ decodedA.isInf || decodedB.isInf ||
2087
+ decodedA.isNan || decodedB.isNan
2088
+ ) {
2089
+ return fp64_div_fp64_normalized(a, b);
2090
+ }
2091
+
2092
+ let exponentA = fp64_f32_finite_exponent(decodedA);
2093
+ let exponentB = fp64_f32_finite_exponent(decodedB);
2094
+ // Correct the quotient near unity so b * q and the remainder stay clear of
2095
+ // both f32 underflow and overflow. The exponent difference is applied once.
2096
+ let normalizedA = fp64_scale_fp64_integer(a, -exponentA);
2097
+ let normalizedB = fp64_scale_fp64_integer(b, -exponentB);
2098
+ let normalizedQuotient = fp64_div_fp64_normalized(normalizedA, normalizedB);
2099
+ return fp64_scale_fp64_integer(normalizedQuotient, exponentA - exponentB);
2100
+ }
2101
+
2102
+ fn fp64_sqrt_fp64_normalized(a: vec2f) -> vec2f {
2103
+ let estimate = sqrt(a.x);
2104
+ let difference = sub_fp64(a, fp64_two_prod_integer(estimate, estimate)).x;
2105
+ let denominator = fp64_round_add_integer(estimate, estimate);
2106
+ let correction = fp64_divide_f32_integer(difference, denominator);
2107
+ return sum_fp64(vec2f(estimate, 0.0), vec2f(correction, 0.0));
2108
+ }
2109
+
2110
+ fn sqrt_fp64(a: vec2f) -> vec2f {
2111
+ let decoded = fp64_decode_f32_bits(bitcast<u32>(a.x));
2112
+ let decodedLow = fp64_decode_f32_bits(bitcast<u32>(a.y));
2113
+ if (decoded.isZero && decodedLow.isZero) {
2114
+ return vec2f(0.0, 0.0);
2115
+ }
2116
+ if (decoded.sign == 1u) {
2117
+ let nanValue = fp64_nan(a.x);
2118
+ return vec2f(nanValue, nanValue);
2119
+ }
2120
+
2121
+ if (decoded.isInf || decoded.isNan) {
2122
+ return fp64_sqrt_fp64_normalized(a);
2123
+ }
2124
+ let exponent = fp64_f32_finite_exponent(decoded);
2125
+ // An even scale lets the final square-root rescale use an integer exponent.
2126
+ let evenExponent = exponent - (exponent & 1);
2127
+ let normalizedA = fp64_scale_fp64_integer(a, -evenExponent);
2128
+ let normalizedRoot = fp64_sqrt_fp64_normalized(normalizedA);
2129
+ return fp64_scale_fp64_integer(normalizedRoot, evenExponent / 2);
2130
+ }
2131
+ #endif
2132
+ `
2133
+ );
2134
+
1676
2135
  // ../../node_modules/@luma.gl/shadertools/dist/modules/math/fp64/fp64-arithmetic-wgsl.js
1677
2136
  var fp64arithmeticWGSL = (
1678
2137
  /* wgsl */
@@ -1683,6 +2142,7 @@ vec2 sqrt_fp64(vec2 a) {
1683
2142
 
1684
2143
  @group(0) @binding(auto) var<uniform> fp64arithmetic : Fp64ArithmeticUniforms;
1685
2144
 
2145
+ #ifndef LUMA_FP64_F32_INPUT_ONLY
1686
2146
  struct Fp64Bits {
1687
2147
  sign: u32,
1688
2148
  exponent: i32,
@@ -1691,11 +2151,14 @@ struct Fp64Bits {
1691
2151
  isInf: bool,
1692
2152
  isNan: bool,
1693
2153
  };
2154
+ #endif
1694
2155
 
2156
+ #ifndef LUMA_FP64_PREDICATE_ONLY
1695
2157
  fn fp64_nan(seed: f32) -> f32 {
1696
2158
  let nanBits = 0x7fc00000u | select(0u, 1u, seed < 0.0);
1697
2159
  return bitcast<f32>(nanBits);
1698
2160
  }
2161
+ #endif
1699
2162
 
1700
2163
  fn fp64_u64_is_zero(value: vec2u) -> bool {
1701
2164
  return value.x == 0u && value.y == 0u;
@@ -1783,6 +2246,7 @@ fn fp64_u64_has_bits_below(value: vec2u, bitCount: u32) -> bool {
1783
2246
  return (value.y & lowMask) != 0u;
1784
2247
  }
1785
2248
 
2249
+ #ifndef LUMA_FP64_F32_INPUT_ONLY
1786
2250
  fn fp64_u64_shift_right_sticky(value: vec2u, shift: u32) -> vec2u {
1787
2251
  var shifted = fp64_u64_shift_right(value, shift);
1788
2252
  if (fp64_u64_has_bits_below(value, shift)) {
@@ -1790,6 +2254,7 @@ fn fp64_u64_shift_right_sticky(value: vec2u, shift: u32) -> vec2u {
1790
2254
  }
1791
2255
  return shifted;
1792
2256
  }
2257
+ #endif
1793
2258
 
1794
2259
  fn fp64_u64_count_leading_zeros(value: vec2u) -> u32 {
1795
2260
  if (value.x != 0u) {
@@ -1813,6 +2278,22 @@ fn fp64_round_shift_right_to_u32(value: vec2u, shift: u32) -> u32 {
1813
2278
  return rounded;
1814
2279
  }
1815
2280
 
2281
+ #ifndef LUMA_FP64_F32_INPUT_ONLY
2282
+ fn fp64_round_shift_right(value: vec2u, shift: u32) -> vec2u {
2283
+ if (shift == 0u) {
2284
+ return value;
2285
+ }
2286
+
2287
+ var rounded = fp64_u64_shift_right(value, shift);
2288
+ let guard = fp64_u64_get_bit(value, shift - 1u);
2289
+ let hasTrailingBits = fp64_u64_has_bits_below(value, shift - 1u);
2290
+ if (guard && (hasTrailingBits || (rounded.y & 1u) == 1u)) {
2291
+ rounded = fp64_u64_add(rounded, vec2u(0u, 1u));
2292
+ }
2293
+ return rounded;
2294
+ }
2295
+ #endif
2296
+
1816
2297
  fn fp64_make_f32_bits_from_u64(sign: u32, significand: vec2u, baseExponent: i32) -> u32 {
1817
2298
  if (fp64_u64_is_zero(significand)) {
1818
2299
  return sign << 31u;
@@ -1860,6 +2341,7 @@ fn fp64_make_f32_bits_from_u64(sign: u32, significand: vec2u, baseExponent: i32)
1860
2341
  return (sign << 31u) | mantissa;
1861
2342
  }
1862
2343
 
2344
+ #ifndef LUMA_FP64_F32_INPUT_ONLY
1863
2345
  fn fp64_decode_bits(bits: vec2u) -> Fp64Bits {
1864
2346
  let sign = bits.x >> 31u;
1865
2347
  let exponentBits = (bits.x >> 20u) & 0x7ffu;
@@ -1886,6 +2368,261 @@ fn fp64_finite_magnitude_compare(a: Fp64Bits, b: Fp64Bits) -> i32 {
1886
2368
  }
1887
2369
  return fp64_u64_compare(a.significand, b.significand);
1888
2370
  }
2371
+ #endif
2372
+
2373
+ #ifndef LUMA_FP64_F32_INPUT_ONLY
2374
+ struct Fp64RawF32Bits {
2375
+ sign: u32,
2376
+ baseExponent: i32,
2377
+ significand: u32,
2378
+ isZero: bool,
2379
+ isInf: bool,
2380
+ isNan: bool,
2381
+ };
2382
+
2383
+ // Decode an f32 as (-1)^sign * significand * 2^baseExponent. This shared
2384
+ // integer representation lets normalization remain independent of the
2385
+ // selected double-single arithmetic implementation.
2386
+ fn fp64_decode_raw_f32_bits(bits: u32) -> Fp64RawF32Bits {
2387
+ let sign = bits >> 31u;
2388
+ let exponentBits = (bits >> 23u) & 0xffu;
2389
+ let fraction = bits & 0x7fffffu;
2390
+
2391
+ if (exponentBits == 0xffu) {
2392
+ return Fp64RawF32Bits(sign, 0, 0u, false, fraction == 0u, fraction != 0u);
2393
+ }
2394
+ if (exponentBits == 0u) {
2395
+ return Fp64RawF32Bits(sign, -149, fraction, fraction == 0u, false, false);
2396
+ }
2397
+ return Fp64RawF32Bits(
2398
+ sign,
2399
+ i32(exponentBits) - 150,
2400
+ 0x800000u | fraction,
2401
+ false,
2402
+ false,
2403
+ false
2404
+ );
2405
+ }
2406
+
2407
+ fn fp64_raw_f32_magnitude_compare(aBits: u32, bBits: u32) -> i32 {
2408
+ let aMagnitude = aBits & 0x7fffffffu;
2409
+ let bMagnitude = bBits & 0x7fffffffu;
2410
+ if (aMagnitude == bMagnitude) {
2411
+ return 0;
2412
+ }
2413
+ return select(-1, 1, aMagnitude > bMagnitude);
2414
+ }
2415
+
2416
+ fn fp64_make_raw_residual_f32_bits(
2417
+ exactSign: u32,
2418
+ exactMagnitude: vec2u,
2419
+ exactBaseExponent: i32,
2420
+ highBits: u32
2421
+ ) -> u32 {
2422
+ if (fp64_u64_is_zero(exactMagnitude)) {
2423
+ return 0u;
2424
+ }
2425
+
2426
+ let high = fp64_decode_raw_f32_bits(highBits);
2427
+ if (high.isInf || high.isNan) {
2428
+ return 0u;
2429
+ }
2430
+ if (high.isZero) {
2431
+ return fp64_make_f32_bits_from_u64(exactSign, exactMagnitude, exactBaseExponent);
2432
+ }
2433
+
2434
+ let commonBaseExponent = min(exactBaseExponent, high.baseExponent);
2435
+ let exactShift = exactBaseExponent - commonBaseExponent;
2436
+ let highShift = high.baseExponent - commonBaseExponent;
2437
+ if (exactShift >= 64 || highShift >= 64) {
2438
+ return 0u;
2439
+ }
2440
+
2441
+ let exactAligned = fp64_u64_shift_left(exactMagnitude, u32(exactShift));
2442
+ let highAligned = fp64_u64_shift_left(vec2u(0u, high.significand), u32(highShift));
2443
+ let comparison = fp64_u64_compare(exactAligned, highAligned);
2444
+ if (comparison == 0) {
2445
+ return 0u;
2446
+ }
2447
+
2448
+ var residualSign = exactSign;
2449
+ var residualMagnitude: vec2u;
2450
+ if (comparison > 0) {
2451
+ residualMagnitude = fp64_u64_sub(exactAligned, highAligned);
2452
+ } else {
2453
+ residualSign = exactSign ^ 1u;
2454
+ residualMagnitude = fp64_u64_sub(highAligned, exactAligned);
2455
+ }
2456
+ return fp64_make_f32_bits_from_u64(
2457
+ residualSign,
2458
+ residualMagnitude,
2459
+ commonBaseExponent
2460
+ );
2461
+ }
2462
+
2463
+ fn fp64_split_raw_accumulator_bits(
2464
+ sign: u32,
2465
+ magnitude: vec2u,
2466
+ baseExponent: i32
2467
+ ) -> vec2u {
2468
+ if (fp64_u64_is_zero(magnitude)) {
2469
+ return vec2u(0u);
2470
+ }
2471
+ let highBits = fp64_make_f32_bits_from_u64(sign, magnitude, baseExponent);
2472
+ let rawLowBits = fp64_make_raw_residual_f32_bits(sign, magnitude, baseExponent, highBits);
2473
+ let lowBits = select(rawLowBits, 0u, (rawLowBits & 0x7fffffffu) == 0u);
2474
+ if ((highBits & 0x7fffffffu) == 0u && (lowBits & 0x7fffffffu) == 0u) {
2475
+ return vec2u(0u);
2476
+ }
2477
+ return vec2u(highBits, lowBits);
2478
+ }
2479
+ #endif
2480
+
2481
+ #ifndef LUMA_FP64_F32_INPUT_ONLY
2482
+ // Round an arithmetic accumulator to binary64 before splitting it. The
2483
+ // aligned add/subtract paths retain three guard bits plus a sticky bit, which
2484
+ // is sufficient for round-to-nearest-even at the binary64 boundary.
2485
+ fn fp64_split_binary64_accumulator_bits(
2486
+ sign: u32,
2487
+ magnitude: vec2u,
2488
+ baseExponent: i32
2489
+ ) -> vec2u {
2490
+ if (fp64_u64_is_zero(magnitude)) {
2491
+ return vec2u(0u);
2492
+ }
2493
+
2494
+ let mostSignificantBit = 63u - fp64_u64_count_leading_zeros(magnitude);
2495
+ let exponent = baseExponent + i32(mostSignificantBit);
2496
+ if (exponent > 1023) {
2497
+ return vec2u((sign << 31u) | 0x7f800000u, 0u);
2498
+ }
2499
+
2500
+ var roundedMagnitude = magnitude;
2501
+ var roundedBaseExponent = baseExponent;
2502
+ if (exponent >= -1022) {
2503
+ if (mostSignificantBit > 52u) {
2504
+ let shift = mostSignificantBit - 52u;
2505
+ roundedMagnitude = fp64_round_shift_right(magnitude, shift);
2506
+ roundedBaseExponent = baseExponent + i32(shift);
2507
+ }
2508
+ } else {
2509
+ let shift = -1074 - baseExponent;
2510
+ if (shift > 0) {
2511
+ roundedMagnitude = fp64_round_shift_right(magnitude, u32(shift));
2512
+ roundedBaseExponent = -1074;
2513
+ }
2514
+ }
2515
+
2516
+ if (fp64_u64_is_zero(roundedMagnitude)) {
2517
+ return vec2u(0u);
2518
+ }
2519
+ return fp64_split_raw_accumulator_bits(sign, roundedMagnitude, roundedBaseExponent);
2520
+ }
2521
+ #endif
2522
+
2523
+ #ifndef LUMA_FP64_PREDICATE_ONLY
2524
+ fn fp64_add_raw_f32_bits(aBits: u32, bBits: u32) -> vec2u {
2525
+ let a = fp64_decode_raw_f32_bits(aBits);
2526
+ let b = fp64_decode_raw_f32_bits(bBits);
2527
+
2528
+ if (a.isNan || b.isNan) {
2529
+ return vec2u(0x7fc00000u, 0u);
2530
+ }
2531
+ if (a.isInf || b.isInf) {
2532
+ if (a.isInf && b.isInf && a.sign != b.sign) {
2533
+ return vec2u(0x7fc00000u, 0u);
2534
+ }
2535
+ return select(vec2u(bBits, 0u), vec2u(aBits, 0u), a.isInf);
2536
+ }
2537
+ if (a.isZero && b.isZero) {
2538
+ return vec2u(0u);
2539
+ }
2540
+ if (a.isZero) {
2541
+ return vec2u(bBits, 0u);
2542
+ }
2543
+ if (b.isZero) {
2544
+ return vec2u(aBits, 0u);
2545
+ }
2546
+
2547
+ let exponentDifference = abs(a.baseExponent - b.baseExponent);
2548
+ if (exponentDifference > 25) {
2549
+ if (fp64_raw_f32_magnitude_compare(aBits, bBits) >= 0) {
2550
+ return vec2u(aBits, bBits);
2551
+ }
2552
+ return vec2u(bBits, aBits);
2553
+ }
2554
+
2555
+ let commonBaseExponent = min(a.baseExponent, b.baseExponent);
2556
+ let aMagnitude = fp64_u64_shift_left(
2557
+ vec2u(0u, a.significand),
2558
+ u32(a.baseExponent - commonBaseExponent)
2559
+ );
2560
+ let bMagnitude = fp64_u64_shift_left(
2561
+ vec2u(0u, b.significand),
2562
+ u32(b.baseExponent - commonBaseExponent)
2563
+ );
2564
+
2565
+ var resultSign = a.sign;
2566
+ var resultMagnitude: vec2u;
2567
+ if (a.sign == b.sign) {
2568
+ resultMagnitude = fp64_u64_add(aMagnitude, bMagnitude);
2569
+ } else {
2570
+ let comparison = fp64_u64_compare(aMagnitude, bMagnitude);
2571
+ if (comparison == 0) {
2572
+ return vec2u(0u);
2573
+ }
2574
+ if (comparison > 0) {
2575
+ resultMagnitude = fp64_u64_sub(aMagnitude, bMagnitude);
2576
+ } else {
2577
+ resultSign = b.sign;
2578
+ resultMagnitude = fp64_u64_sub(bMagnitude, aMagnitude);
2579
+ }
2580
+ }
2581
+
2582
+ return fp64_split_raw_accumulator_bits(
2583
+ resultSign,
2584
+ resultMagnitude,
2585
+ commonBaseExponent
2586
+ );
2587
+ }
2588
+ #endif
2589
+
2590
+ #ifndef LUMA_FP64_F32_INPUT_ONLY
2591
+ fn fp64_add_aligned_magnitudes_to_fp64_bits(
2592
+ sign: u32,
2593
+ larger: Fp64Bits,
2594
+ smaller: Fp64Bits
2595
+ ) -> vec2u {
2596
+ let largeSignificand = fp64_u64_shift_left(larger.significand, 3u);
2597
+ let smallSignificand = fp64_u64_shift_right_sticky(
2598
+ fp64_u64_shift_left(smaller.significand, 3u),
2599
+ u32(larger.exponent - smaller.exponent)
2600
+ );
2601
+ let resultSignificand = fp64_u64_add(largeSignificand, smallSignificand);
2602
+ return fp64_split_binary64_accumulator_bits(
2603
+ sign,
2604
+ resultSignificand,
2605
+ larger.exponent - 55
2606
+ );
2607
+ }
2608
+
2609
+ fn fp64_sub_aligned_magnitudes_to_fp64_bits(
2610
+ sign: u32,
2611
+ larger: Fp64Bits,
2612
+ smaller: Fp64Bits
2613
+ ) -> vec2u {
2614
+ let largeSignificand = fp64_u64_shift_left(larger.significand, 3u);
2615
+ let smallSignificand = fp64_u64_shift_right_sticky(
2616
+ fp64_u64_shift_left(smaller.significand, 3u),
2617
+ u32(larger.exponent - smaller.exponent)
2618
+ );
2619
+ let resultSignificand = fp64_u64_sub(largeSignificand, smallSignificand);
2620
+ return fp64_split_binary64_accumulator_bits(
2621
+ sign,
2622
+ resultSignificand,
2623
+ larger.exponent - 55
2624
+ );
2625
+ }
1889
2626
 
1890
2627
  fn fp64_add_aligned_magnitudes_to_f32_bits(sign: u32, larger: Fp64Bits, smaller: Fp64Bits) -> u32 {
1891
2628
  let largeSignificand = fp64_u64_shift_left(larger.significand, 3u);
@@ -1955,6 +2692,58 @@ fn sub_fp64u32_to_f32(aBits: vec2u, bBits: vec2u) -> f32 {
1955
2692
  return bitcast<f32>(sub_fp64u32_to_f32_bits(aBits, bBits));
1956
2693
  }
1957
2694
 
2695
+ // Subtract two raw binary64 values, round once to binary64, then split the
2696
+ // result into normalized f32 limbs. Finite results must fit within the f32
2697
+ // exponent range; larger magnitudes map to infinity and smaller magnitudes
2698
+ // map to zero. The input words use canonical high/low word order.
2699
+ fn sub_fp64u32_to_fp64_bits(aBits: vec2u, bBits: vec2u) -> vec2u {
2700
+ let a = fp64_decode_bits(aBits);
2701
+ let b = fp64_decode_bits(bBits);
2702
+ let bSubtractionSign = b.sign ^ 1u;
2703
+
2704
+ if (a.isNan || b.isNan) {
2705
+ return vec2u(0x7fc00000u, 0u);
2706
+ }
2707
+ if (a.isInf && b.isInf) {
2708
+ if (a.sign == bSubtractionSign) {
2709
+ return vec2u((a.sign << 31u) | 0x7f800000u, 0u);
2710
+ }
2711
+ return vec2u(0x7fc00000u, 0u);
2712
+ }
2713
+ if (a.isInf) {
2714
+ return vec2u((a.sign << 31u) | 0x7f800000u, 0u);
2715
+ }
2716
+ if (b.isInf) {
2717
+ return vec2u((bSubtractionSign << 31u) | 0x7f800000u, 0u);
2718
+ }
2719
+ if (a.isZero && b.isZero) {
2720
+ return vec2u(0u);
2721
+ }
2722
+
2723
+ let magnitudeComparison = fp64_finite_magnitude_compare(a, b);
2724
+ if (a.sign == bSubtractionSign) {
2725
+ if (magnitudeComparison >= 0) {
2726
+ return fp64_add_aligned_magnitudes_to_fp64_bits(a.sign, a, b);
2727
+ }
2728
+ return fp64_add_aligned_magnitudes_to_fp64_bits(a.sign, b, a);
2729
+ }
2730
+
2731
+ if (magnitudeComparison == 0) {
2732
+ return vec2u(0u);
2733
+ }
2734
+ if (magnitudeComparison > 0) {
2735
+ return fp64_sub_aligned_magnitudes_to_fp64_bits(a.sign, a, b);
2736
+ }
2737
+ return fp64_sub_aligned_magnitudes_to_fp64_bits(bSubtractionSign, b, a);
2738
+ }
2739
+
2740
+ fn sub_fp64u32_to_fp64(aBits: vec2u, bBits: vec2u) -> vec2f {
2741
+ let resultBits = sub_fp64u32_to_fp64_bits(aBits, bBits);
2742
+ return vec2f(bitcast<f32>(resultBits.x), bitcast<f32>(resultBits.y));
2743
+ }
2744
+ #endif
2745
+
2746
+ #ifndef LUMA_FP64_PREDICATE_ONLY
1958
2747
  fn fp64_runtime_zero() -> f32 {
1959
2748
  return fp64arithmetic.ONE * 0.0;
1960
2749
  }
@@ -1966,7 +2755,11 @@ fn prevent_fp64_optimization(value: f32) -> f32 {
1966
2755
  return value;
1967
2756
  #endif
1968
2757
  }
2758
+ #endif
1969
2759
 
2760
+ #ifdef LUMA_FP64_INTEGER_ARITHMETIC
2761
+ ${fp64arithmeticWGSLInteger}
2762
+ #else
1970
2763
  fn split(a: f32) -> vec2f {
1971
2764
  let splitValue = prevent_fp64_optimization(fp64arithmetic.SPLIT + fp64_runtime_zero());
1972
2765
  let t = prevent_fp64_optimization(a * splitValue);
@@ -2117,6 +2910,7 @@ fn mul_fp64(a: vec2f, b: vec2f) -> vec2f {
2117
2910
  return prod;
2118
2911
  }
2119
2912
 
2913
+ #ifndef LUMA_FP64_PREDICATE_ONLY
2120
2914
  fn div_fp64(a: vec2f, b: vec2f) -> vec2f {
2121
2915
  let xn = prevent_fp64_optimization(1.0 / b.x);
2122
2916
  let yn = mul_fp64(a, vec2f(xn, fp64_runtime_zero()));
@@ -2149,6 +2943,97 @@ fn sqrt_fp64(a: vec2f) -> vec2f {
2149
2943
  return sum_fp64(vec2f(yn, 0.0), prod);
2150
2944
  #endif
2151
2945
  }
2946
+ #endif
2947
+ #endif
2948
+
2949
+ #ifndef LUMA_FP64_PREDICATE_ONLY
2950
+ fn fp64_f32_bits_is_nan(bits: u32) -> bool {
2951
+ return (bits & 0x7fffffffu) > 0x7f800000u;
2952
+ }
2953
+
2954
+ fn fp64_f32_bits_is_inf(bits: u32) -> bool {
2955
+ return (bits & 0x7fffffffu) == 0x7f800000u;
2956
+ }
2957
+
2958
+ fn fp64_compare_f32_bits(aBits: u32, bBits: u32) -> i32 {
2959
+ let aMagnitude = aBits & 0x7fffffffu;
2960
+ let bMagnitude = bBits & 0x7fffffffu;
2961
+ if (aMagnitude == 0u && bMagnitude == 0u) {
2962
+ return 0;
2963
+ }
2964
+ let aSign = aBits >> 31u;
2965
+ let bSign = bBits >> 31u;
2966
+ if (aSign != bSign) {
2967
+ return select(1, -1, aSign == 1u);
2968
+ }
2969
+ if (aMagnitude == bMagnitude) {
2970
+ return 0;
2971
+ }
2972
+ let magnitudeComparison = select(-1, 1, aMagnitude > bMagnitude);
2973
+ return select(magnitudeComparison, -magnitudeComparison, aSign == 1u);
2974
+ }
2975
+
2976
+ // Normalize an arbitrary pair of finite f32 limbs with integer accumulation.
2977
+ // This is independent of LUMA_FP64_INTEGER_ARITHMETIC and canonicalizes every
2978
+ // representation of zero to vec2f(+0.0, +0.0).
2979
+ fn normalize_fp64(value: vec2f) -> vec2f {
2980
+ let resultBits = fp64_add_raw_f32_bits(bitcast<u32>(value.x), bitcast<u32>(value.y));
2981
+ return vec2f(bitcast<f32>(resultBits.x), bitcast<f32>(resultBits.y));
2982
+ }
2983
+
2984
+ fn is_nan_fp64(value: vec2f) -> bool {
2985
+ let normalized = normalize_fp64(value);
2986
+ return fp64_f32_bits_is_nan(bitcast<u32>(normalized.x)) ||
2987
+ fp64_f32_bits_is_nan(bitcast<u32>(normalized.y));
2988
+ }
2989
+
2990
+ fn is_finite_fp64(value: vec2f) -> bool {
2991
+ let normalized = normalize_fp64(value);
2992
+ let highBits = bitcast<u32>(normalized.x);
2993
+ let lowBits = bitcast<u32>(normalized.y);
2994
+ return !fp64_f32_bits_is_nan(highBits) && !fp64_f32_bits_is_nan(lowBits) &&
2995
+ !fp64_f32_bits_is_inf(highBits) && !fp64_f32_bits_is_inf(lowBits);
2996
+ }
2997
+
2998
+ // Returns -1, 0, or 1. NaN is unordered and returns 0; call is_nan_fp64 or
2999
+ // is_finite_fp64 first when 0 must mean a finite zero.
3000
+ fn sign_fp64(value: vec2f) -> i32 {
3001
+ let normalized = normalize_fp64(value);
3002
+ let highBits = bitcast<u32>(normalized.x);
3003
+ let lowBits = bitcast<u32>(normalized.y);
3004
+ if (fp64_f32_bits_is_nan(highBits) || fp64_f32_bits_is_nan(lowBits)) {
3005
+ return 0;
3006
+ }
3007
+ if ((highBits & 0x7fffffffu) != 0u) {
3008
+ return select(1, -1, (highBits >> 31u) == 1u);
3009
+ }
3010
+ if ((lowBits & 0x7fffffffu) != 0u) {
3011
+ return select(1, -1, (lowBits >> 31u) == 1u);
3012
+ }
3013
+ return 0;
3014
+ }
3015
+
3016
+ // Compares double-single values and returns -1, 0, or 1. NaN is unordered
3017
+ // and returns 0; callers that require equality semantics must first check
3018
+ // is_nan_fp64 or is_finite_fp64.
3019
+ fn compare_fp64(a: vec2f, b: vec2f) -> i32 {
3020
+ let normalizedA = normalize_fp64(a);
3021
+ let normalizedB = normalize_fp64(b);
3022
+ let aHighBits = bitcast<u32>(normalizedA.x);
3023
+ let aLowBits = bitcast<u32>(normalizedA.y);
3024
+ let bHighBits = bitcast<u32>(normalizedB.x);
3025
+ let bLowBits = bitcast<u32>(normalizedB.y);
3026
+ if (fp64_f32_bits_is_nan(aHighBits) || fp64_f32_bits_is_nan(aLowBits) ||
3027
+ fp64_f32_bits_is_nan(bHighBits) || fp64_f32_bits_is_nan(bLowBits)) {
3028
+ return 0;
3029
+ }
3030
+ let highComparison = fp64_compare_f32_bits(aHighBits, bHighBits);
3031
+ if (highComparison != 0) {
3032
+ return highComparison;
3033
+ }
3034
+ return fp64_compare_f32_bits(aLowBits, bLowBits);
3035
+ }
3036
+ #endif
2152
3037
  `
2153
3038
  );
2154
3039
 
@@ -3779,6 +4664,9 @@ in vec2 clip_commonPosition;
3779
4664
  clipByInstance = Boolean(this.props.clipByInstance);
3780
4665
  }
3781
4666
  this.state.clipByInstance = clipByInstance;
4667
+ if (this.context.device.type === "webgpu") {
4668
+ return {};
4669
+ }
3782
4670
  return clipByInstance ? {
3783
4671
  modules: [shaderModuleVs],
3784
4672
  inject: injectionVs
@@ -3803,6 +4691,10 @@ in vec2 clip_commonPosition;
3803
4691
  Math.max(corner0[1], corner1[1])
3804
4692
  ];
3805
4693
  }
4694
+ if (this.context.device.type === "webgpu") {
4695
+ clipProps.enabled = true;
4696
+ clipProps.mode = this.state.clipByInstance ? "instance" : "geometry";
4697
+ }
3806
4698
  this.setShaderModuleProps({ clip: clipProps });
3807
4699
  }
3808
4700
  };