diff --git a/package-lock.json b/package-lock.json index fb184f9..ad64602 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,14 +13,14 @@ "devDependencies": { "@webgpu/types": "^0.1", "copyfiles": "^2.4", - "esbuild": "^0.19", + "esbuild": "^0.23", "typescript": "^5" } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", - "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz", + "integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==", "cpu": [ "ppc64" ], @@ -30,13 +30,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", - "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz", + "integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==", "cpu": [ "arm" ], @@ -46,13 +46,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", - "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz", + "integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==", "cpu": [ "arm64" ], @@ -62,13 +62,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", - "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz", + "integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==", "cpu": [ "x64" ], @@ -78,13 +78,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", - "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", + "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", "cpu": [ "arm64" ], @@ -94,13 +94,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", - "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz", + "integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==", "cpu": [ "x64" ], @@ -110,13 +110,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", - "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz", + "integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==", "cpu": [ "arm64" ], @@ -126,13 +126,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", - "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz", + "integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==", "cpu": [ "x64" ], @@ -142,13 +142,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", - "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz", + "integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==", "cpu": [ "arm" ], @@ -158,13 +158,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", - "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz", + "integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==", "cpu": [ "arm64" ], @@ -174,13 +174,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", - "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz", + "integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==", "cpu": [ "ia32" ], @@ -190,13 +190,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", - "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz", + "integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==", "cpu": [ "loong64" ], @@ -206,13 +206,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", - "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz", + "integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==", "cpu": [ "mips64el" ], @@ -222,13 +222,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", - "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz", + "integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==", "cpu": [ "ppc64" ], @@ -238,13 +238,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", - "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz", + "integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==", "cpu": [ "riscv64" ], @@ -254,13 +254,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", - "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz", + "integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==", "cpu": [ "s390x" ], @@ -270,13 +270,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", - "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz", + "integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==", "cpu": [ "x64" ], @@ -286,13 +286,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", - "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz", + "integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==", "cpu": [ "x64" ], @@ -302,13 +302,29 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz", + "integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", - "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz", + "integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==", "cpu": [ "x64" ], @@ -318,13 +334,13 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", - "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz", + "integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==", "cpu": [ "x64" ], @@ -334,13 +350,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", - "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz", + "integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==", "cpu": [ "arm64" ], @@ -350,13 +366,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", - "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz", + "integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==", "cpu": [ "ia32" ], @@ -366,13 +382,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", - "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz", + "integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==", "cpu": [ "x64" ], @@ -382,7 +398,7 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@kurkle/color": { @@ -514,41 +530,42 @@ "dev": true }, "node_modules/esbuild": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", - "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", + "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", "dev": true, "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.19.12", - "@esbuild/android-arm": "0.19.12", - "@esbuild/android-arm64": "0.19.12", - "@esbuild/android-x64": "0.19.12", - "@esbuild/darwin-arm64": "0.19.12", - "@esbuild/darwin-x64": "0.19.12", - "@esbuild/freebsd-arm64": "0.19.12", - "@esbuild/freebsd-x64": "0.19.12", - "@esbuild/linux-arm": "0.19.12", - "@esbuild/linux-arm64": "0.19.12", - "@esbuild/linux-ia32": "0.19.12", - "@esbuild/linux-loong64": "0.19.12", - "@esbuild/linux-mips64el": "0.19.12", - "@esbuild/linux-ppc64": "0.19.12", - "@esbuild/linux-riscv64": "0.19.12", - "@esbuild/linux-s390x": "0.19.12", - "@esbuild/linux-x64": "0.19.12", - "@esbuild/netbsd-x64": "0.19.12", - "@esbuild/openbsd-x64": "0.19.12", - "@esbuild/sunos-x64": "0.19.12", - "@esbuild/win32-arm64": "0.19.12", - "@esbuild/win32-ia32": "0.19.12", - "@esbuild/win32-x64": "0.19.12" + "@esbuild/aix-ppc64": "0.23.0", + "@esbuild/android-arm": "0.23.0", + "@esbuild/android-arm64": "0.23.0", + "@esbuild/android-x64": "0.23.0", + "@esbuild/darwin-arm64": "0.23.0", + "@esbuild/darwin-x64": "0.23.0", + "@esbuild/freebsd-arm64": "0.23.0", + "@esbuild/freebsd-x64": "0.23.0", + "@esbuild/linux-arm": "0.23.0", + "@esbuild/linux-arm64": "0.23.0", + "@esbuild/linux-ia32": "0.23.0", + "@esbuild/linux-loong64": "0.23.0", + "@esbuild/linux-mips64el": "0.23.0", + "@esbuild/linux-ppc64": "0.23.0", + "@esbuild/linux-riscv64": "0.23.0", + "@esbuild/linux-s390x": "0.23.0", + "@esbuild/linux-x64": "0.23.0", + "@esbuild/netbsd-x64": "0.23.0", + "@esbuild/openbsd-arm64": "0.23.0", + "@esbuild/openbsd-x64": "0.23.0", + "@esbuild/sunos-x64": "0.23.0", + "@esbuild/win32-arm64": "0.23.0", + "@esbuild/win32-ia32": "0.23.0", + "@esbuild/win32-x64": "0.23.0" } }, "node_modules/escalade": { @@ -786,9 +803,9 @@ } }, "node_modules/typescript": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.2.tgz", - "integrity": "sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/package.json b/package.json index 96b484a..0959b4a 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "devDependencies": { "@webgpu/types": "^0.1", "copyfiles": "^2.4", - "esbuild": "^0.19", + "esbuild": "^0.23", "typescript": "^5" }, "scripts": { diff --git a/src/scripts/GPURenderRunner.ts b/src/scripts/GPURenderRunner.ts index 17b2223..d5f7efe 100644 --- a/src/scripts/GPURenderRunner.ts +++ b/src/scripts/GPURenderRunner.ts @@ -27,7 +27,7 @@ export class GPURenderRunner implements GPURunner { async Init() { await this.runner.Init() let renderInfo = this.runner.getRenderInfo() - this.render = new Render(renderInfo.textures, ...renderInfo.fragmentShaderFilenames) + this.render = new Render(renderInfo.textures,[], ...renderInfo.fragmentShaderFilenames) await this.render.Init() } diff --git a/src/scripts/RunGPURunner.ts b/src/scripts/RunGPURunner.ts index 3a02740..c1a2e68 100644 --- a/src/scripts/RunGPURunner.ts +++ b/src/scripts/RunGPURunner.ts @@ -126,10 +126,9 @@ async function HandleAsyncAnimation(runner: GPURunner) { GPU.device.queue.onSubmittedWorkDone().then(() => queuePartFinished()) } // fill the queue - queuePartFinished().then(r => { - }) - queuePartFinished().then(r => { - }) + const noop = () => {}; + queuePartFinished().then(noop) + queuePartFinished().then(noop) let renderFinished = true let frame = async () => { diff --git a/src/scripts/fluid/advect/advect.ts b/src/scripts/fluid/advect/advect.ts index 50fb5a8..16a00d0 100755 --- a/src/scripts/fluid/advect/advect.ts +++ b/src/scripts/fluid/advect/advect.ts @@ -77,6 +77,11 @@ export class Advect { }); } + public async Destroy() { + this.velocitydest.destroy(); + } + + GetCommandBuffer(): GPUCommandBuffer { let encoder: GPUCommandEncoder = GPU.CreateCommandEncoder(); diff --git a/src/scripts/fluid/div/div.ts b/src/scripts/fluid/div/div.ts index 0826d10..5c4e162 100755 --- a/src/scripts/fluid/div/div.ts +++ b/src/scripts/fluid/div/div.ts @@ -70,6 +70,11 @@ export class Div { }); } + public async Destroy() { + this.div.destroy(); + } + + GetCommandBuffer() : GPUCommandBuffer { let encoder: GPUCommandEncoder = GPU.CreateCommandEncoder(); { diff --git a/src/scripts/fluid/fluid.ts b/src/scripts/fluid/fluid.ts index f3bfa17..3792afa 100644 --- a/src/scripts/fluid/fluid.ts +++ b/src/scripts/fluid/fluid.ts @@ -31,8 +31,6 @@ export class Fluid extends GPUAbstractRunner { public getType(): RunnerType { return RunnerType.ASYNCANIM } - public async Destroy() { - } n: number; m: number; @@ -109,6 +107,19 @@ export class Fluid extends GPUAbstractRunner { //await GPU.Render(poisson.pressurea); } + public async Destroy() { + await this.project.Destroy() + await this.poisson.Destroy() + await this.div.Destroy() + await this.transport.Destroy() + await this.advect.Destroy() + await this.source.Destroy() + this.velocity.destroy() + this.density.destroy() + this.flags.destroy() + } + + async Run() { GPU.device.queue.submit([ @@ -141,12 +152,12 @@ export class Fluid extends GPUAbstractRunner { vel[(j * this.width + i) * 4 + 1] = toHalf(x * 0.03); } */ + for (let j = 200; j < this.height-200; j++) for (let i = 200; i < this.width-200; i++) { - vel[(j * this.width + i) * 4 + 0] = toHalf(0.3); + vel[(j * this.width + i) * 4 + 0] = toHalf(0.); vel[(j * this.width + i) * 4 + 1] = toHalf(0.); } - this.velocity = await GPU.CreateTextureFromArrayBuffer(this.width, this.height, "rgba16float", vel.buffer); } @@ -157,8 +168,10 @@ export class Fluid extends GPUAbstractRunner { for (let i = 0; i < this.width; i++) { let x: number = i - 256; let y: number = j - 256; - density[(j * this.width + i) * 4 + 0] = toHalf(Math.exp(-(x * x + y * y) * 0.001)); - density[(j * this.width + i) * 4 + 3] = toHalf(1.0); + //density[(j * this.width + i) * 4 + 0] = toHalf(Math.exp(-(x * x + y * y) * 0.001)); + // density[(j * this.width + i) * 4 + 3] = toHalf(1.0); + density[(j * this.width + i) * 4 + 0] = toHalf(0.); + density[(j * this.width + i) * 4 + 3] = toHalf(0.); } this.density = await GPU.CreateTextureFromArrayBuffer(this.width, this.height, "rgba16float", density.buffer); } @@ -167,8 +180,8 @@ export class Fluid extends GPUAbstractRunner { let flags = new Uint32Array(this.width * this.height*4); const F = 0x0001 // is Fluid - const B_u = 0x0002 /* obstacle cells adjacent to fluid cells */ - const B_d = 0x0004 /* in the respective direction */ + const B_u = 0x0002 // obstacle cells adjacent to fluid cells + const B_d = 0x0004 // in the respective direction const B_l = 0x0008 const B_r = 0x0010 @@ -180,7 +193,7 @@ export class Fluid extends GPUAbstractRunner { // is fluid for (let j = 1; j < this.height-1; j++) for (let i = 1; i < this.width-1; i++) { - flags[(j * this.width + i)*4] = 1; // is fluid + flags[(j * this.width + i)*4] = F; // is fluid } for (let i = 1; i < this.width - 1; i++) { diff --git a/src/scripts/fluid/poisson/jacobi2.wgsl b/src/scripts/fluid/poisson/jacobi2.wgsl deleted file mode 100755 index 9c99627..0000000 --- a/src/scripts/fluid/poisson/jacobi2.wgsl +++ /dev/null @@ -1,42 +0,0 @@ -@group(0) @binding(0) var pressuresrc: texture_2d; -@group(0) @binding(1) var pressuredest: texture_storage_2d; -@group(0) @binding(2) var rhs: texture_2d; -@group(0) @binding(3) var scaleedges: texture_2d; -@group(0) @binding(4) var scalecenter: texture_2d; - -@compute @workgroup_size(8, 8) -fn main(@builtin(global_invocation_id) global_id: vec3) { - let pixel_coords = vec2(global_id.xy) + 1; - - let se = textureLoad(scaleedges, pixel_coords, 0); - let sc = textureLoad(scalecenter, pixel_coords, 0).r; - - let div = textureLoad(rhs, pixel_coords, 0).r; - - let c = textureLoad(pressuresrc, pixel_coords, 0).r; - var l = textureLoad(pressuresrc, pixel_coords + vec2(-1, 0), 0).r; - var r = textureLoad(pressuresrc, pixel_coords + vec2( 1, 0), 0).r; - var t = textureLoad(pressuresrc, pixel_coords + vec2( 0, 1), 0).r; - var b = textureLoad(pressuresrc, pixel_coords + vec2( 0, -1), 0).r; - - var dot = dot(vec4(l, r, t, b), se); - - var pressure: f32 = (dot + c*sc - div) * 0.25; - //let pressure: f32 = (l+r+t+b - div) * 0.25; - //let w = 1.7; - //pressure = (1. - w) * c + w * pressure; - - textureStore(pressuredest, pixel_coords, vec4(pressure, 0., 0., 1.)); -} - -/* -6.451 TFlops -= 6.451 * 10^12 -pro Frame bei 60FPS: -512*512*20*60*21 -*/ - - - - - diff --git a/src/scripts/fluid/poisson/poisson.ts b/src/scripts/fluid/poisson/poisson.ts index 1dff80c..9c260c6 100755 --- a/src/scripts/fluid/poisson/poisson.ts +++ b/src/scripts/fluid/poisson/poisson.ts @@ -177,6 +177,11 @@ export class Poisson { }); } + public async Destroy() { + this.pressurea.destroy(); + this.pressureb.destroy(); + } + GetCommandBuffer() : GPUCommandBuffer { let encoder: GPUCommandEncoder = GPU.CreateCommandEncoder(); diff --git a/src/scripts/fluid/project/project.ts b/src/scripts/fluid/project/project.ts index 94a4886..c74b372 100755 --- a/src/scripts/fluid/project/project.ts +++ b/src/scripts/fluid/project/project.ts @@ -79,6 +79,10 @@ export class Project { }); } + public async Destroy() { + this.velocitydest.destroy(); + } + GetCommandBuffer() : GPUCommandBuffer { let encoder: GPUCommandEncoder = GPU.CreateCommandEncoder(); { diff --git a/src/scripts/fluid/source/source.ts b/src/scripts/fluid/source/source.ts index 700e1d6..bb28af0 100755 --- a/src/scripts/fluid/source/source.ts +++ b/src/scripts/fluid/source/source.ts @@ -1,5 +1,6 @@ import {GPU} from "../../webgpu/gpu"; import {Texture} from "../../webgpu/texture"; +import {Buffer} from "../../webgpu/buffer"; export class Source { width: number; @@ -16,6 +17,9 @@ export class Source { pipeline_layout: GPUPipelineLayout; compute_pipeline: GPUComputePipeline; + stagingBuffer: Buffer + stagingData: Float32Array + constructor(velocity: Texture, density: Texture, flags: Texture) { this.velocitysrc = velocity; this.densitysrc = density; @@ -30,6 +34,9 @@ export class Source { this.velocitydest = GPU.CreateTexture(this.velocitysrc.width, this.velocitysrc.height, this.velocitysrc.format); this.densitydest = GPU.CreateTexture(this.densitysrc.width, this.densitysrc.height, this.densitysrc.format); + this.stagingBuffer = GPU.CreateUniformBuffer(4 * 4) // must be a multiple of 16 bytes + this.stagingData = new Float32Array(4) + this.bind_group_layout = GPU.device.createBindGroupLayout({ entries: [{ binding: 0, @@ -51,6 +58,10 @@ export class Source { binding: 4, texture: {sampleType: "sint"}, visibility: GPUShaderStage.COMPUTE + }, { + binding: 5, + buffer: {type: "uniform", minBindingSize: 4 * 4}, + visibility: GPUShaderStage.COMPUTE }] }); @@ -71,6 +82,9 @@ export class Source { }, { binding: 4, resource: this.flags.textureView + }, { + binding: 5, + resource: this.stagingBuffer.resource }] }); @@ -84,7 +98,17 @@ export class Source { }); } + public async Destroy() { + this.velocitydest.destroy(); + this.densitydest.destroy(); + } + GetCommandBuffer(): GPUCommandBuffer { + this.stagingData[0] = GPU.mouseCoordinate.x; // set iMouseX + this.stagingData[1] = GPU.mouseCoordinate.y; // set iMouseY + this.stagingData[2] = GPU.mouseCoordinate.wheel; + this.stagingData[3] += 1.; // increase iFrame + GPU.device.queue.writeBuffer(this.stagingBuffer.buffer, 0, this.stagingData) let encoder: GPUCommandEncoder = GPU.CreateCommandEncoder(); { diff --git a/src/scripts/fluid/source/source.wgsl b/src/scripts/fluid/source/source.wgsl index 480acea..358a67d 100755 --- a/src/scripts/fluid/source/source.wgsl +++ b/src/scripts/fluid/source/source.wgsl @@ -1,14 +1,29 @@ +struct StagingBuffer { + iMouse: vec2f, + wheel: f32, + iFrame: f32 +}; + @group(0) @binding(0) var velocity_src: texture_2d; @group(0) @binding(1) var velocity_dest: texture_storage_2d; @group(0) @binding(2) var density_src: texture_2d; @group(0) @binding(3) var density_dest: texture_storage_2d; @group(0) @binding(4) var flags: texture_2d; +@group(0) @binding(5) var staging: StagingBuffer; + +var mouse_pos = vec2(0.); +var mouse_wheel: f32 = 0.; -@compute @workgroup_size(2, 2) +fn sphere(p: vec2, r: f32) -> f32 { + return length(p) - r; +} + +@compute @workgroup_size(8, 8) fn main(@builtin(global_invocation_id) global_id: vec3) { var dims = vec2(textureDimensions(velocity_src)); let pixel_coords = vec2(global_id.xy); + var v = textureLoad(velocity_src, pixel_coords, 0); var d = textureLoad(density_src, pixel_coords, 0); @@ -25,10 +40,24 @@ fn main(@builtin(global_invocation_id) global_id: vec3) { } } + //mouse_pos = ((staging.iMouse.xy / vec2(dims.xy))*2.0 - 1.0) * vec2f(1., 1.); + mouse_pos = staging.iMouse.xy; + mouse_wheel = staging.wheel; + + //let dist = sphere(vec2(pixel_coords) - mouse_pos, (-mouse_wheel*0.005+0.05)); + let dist = sphere(vec2(pixel_coords) - mouse_pos, -10.*mouse_wheel + 10.); + if (dist < 0) { + //v = vec4(0.0); + v *= 0.5; + d = vec4(1.0, 0., 0., 1.); + } + +/* if (((pixel_coords.x > 250)) && (pixel_coords.x < 260) && ((pixel_coords.y > 250)) && (pixel_coords.y < 260)) { v = vec4(0.0); + d = vec4(1.0, 0., 0., 0.); } - +*/ textureStore(velocity_dest, pixel_coords, v); textureStore(density_dest, pixel_coords, d); } \ No newline at end of file diff --git a/src/scripts/fluid/transport/transport.ts b/src/scripts/fluid/transport/transport.ts index 3d48e3a..8a79a7c 100755 --- a/src/scripts/fluid/transport/transport.ts +++ b/src/scripts/fluid/transport/transport.ts @@ -104,6 +104,10 @@ export class Transport { }); } + public async Destroy() { + this.textureb.destroy(); + } + GetCommandBuffer() : GPUCommandBuffer { let encoder: GPUCommandEncoder = GPU.CreateCommandEncoder(); { diff --git a/src/scripts/light/light.ts b/src/scripts/light/light.ts index 814ce16..75e7364 100644 --- a/src/scripts/light/light.ts +++ b/src/scripts/light/light.ts @@ -70,6 +70,7 @@ export class LightPropagation extends GPUAbstractRunner { console.log("Create Render") this.render = new Render( [this.textureDest, this.scene.emitter], + [], "scripts/light/common.wgsl", "scripts/light/distance.wgsl", "scripts/light/aces-tone-mapping.wgsl") await this.render.Init() diff --git a/src/scripts/light2/light.ts b/src/scripts/light2/light.ts index 35df186..4c7802a 100644 --- a/src/scripts/light2/light.ts +++ b/src/scripts/light2/light.ts @@ -74,6 +74,7 @@ export class LightPropagation2 extends GPUAbstractRunner { console.log("Create Render") this.render = new Render( [this.textureSrc, this.scene.emitter], + [], "scripts/light2/common.wgsl", "scripts/light2/aces-tone-mapping.wgsl") await this.render.Init() diff --git a/src/scripts/light_buffer/aces-tone-mapping.wgsl b/src/scripts/light_buffer/aces-tone-mapping.wgsl new file mode 100644 index 0000000..846cd40 --- /dev/null +++ b/src/scripts/light_buffer/aces-tone-mapping.wgsl @@ -0,0 +1,122 @@ +// ACES tonemapper +fn ACES(x: vec3f) -> vec3f { + const a: f32 = 2.51; + const b: f32 = .03; + const c: f32 = 2.43; + const d: f32 = .59; + const e: f32 = .14; + return (x * (a * x + b)) / (x * (c * x + d) + e); +} + +// ACES fitted +// from https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl + +const ACESInputMat = mat3x3f( + 0.59719, 0.35458, 0.04823, + 0.07600, 0.90834, 0.01566, + 0.02840, 0.13383, 0.83777 +); + +// ODT_SAT => XYZ => D60_2_D65 => sRGB +const ACESOutputMat = mat3x3f( + 1.60475, -0.53108, -0.07367, + -0.10208, 1.10813, -0.00605, + -0.00327, -0.07276, 1.07602 +); + +fn RRTAndODTFit(v: vec3f) -> vec3f { + let a: vec3f = v * (v + 0.0245786) - 0.000090537; + let b: vec3f = v * (0.983729 * v + 0.4329510) + 0.238081; + return a / b; +} + +fn ACESFitted(_color: vec3f) -> vec3f { + var color: vec3f = _color * ACESInputMat; + + // Apply RRT and ODT + color = RRTAndODTFit(color); + + color = color * ACESOutputMat; + + // Clamp to [0, 1] + color = clamp(color, vec3f(0.0), vec3f(1.0)); + + return color; +} +//--------------------------------------------------------------------------------- + + +struct ColorCH { + r: vec3f, + g: vec3f, + b: vec3f +}; + +//--------------------------------------------------------------------------------- + +fn linear_srgb(x: f32) -> f32 { + return mix(1.055*pow(x, 1./2.4) - 0.055, 12.92*x, step(x,0.0031308)); +} + +fn linear_srgb_vec(x: vec3f) -> vec3f { + return mix(1.055*pow(x, vec3f(1./2.4)) - 0.055, 12.92*x, step(x,vec3f(0.0031308))); +} + +fn srgb_linear(x: f32) -> f32 { + return mix(pow((x + 0.055)/1.055,2.4), x / 12.92, step(x,0.04045)); +} + +fn srgb_linear_vec(x: vec3f) -> vec3f { + return mix(pow((x + 0.055)/1.055,vec3f(2.4)), x / 12.92, step(x,vec3f(0.04045))); +} + +struct Cell { + // speherical harmonics for n=0 and n=1 + chr: vec3f, + chg: vec3f, + chb: vec3f, + + Em : vec3f, // emitted light + translucency: f32 +}; + + +@group(0) @binding(0) var scene: texture_2d_array; +@group(0) @binding(1) var state: array; // this is used as both input and output + + +struct VertexOutput { + @builtin(position) Position : vec4f, + @location(0) fragUV : vec2f +}; + +@fragment +fn main(data: VertexOutput) -> @location(0) vec4f { + var iResolution = vec2f(512, 512); + let p = vec2i(data.fragUV*iResolution); + + var idx = u32(p.x + p.y * 512); + + let ch = ColorCH( + state[idx].chr, // incoming red light from neighbor as circular harmonics + state[idx].chg, // incoming green light from neighbor as circular harmonics + state[idx].chb, // incoming blue light from neighbor as circular harmonics + ); + +/* + + let ch = ColorCH( + textureLoad(texture, p, 0, 0).xyz, // emitted red light as circular harmonics + textureLoad(texture, p, 1, 0).xyz, // emitted green light as circular harmonics + textureLoad(texture, p, 2, 0).xyz, // emitted blue light as circular harmonics + ); +*/ + let col = vec3(ch.r.z, ch.g.z, ch.b.z)*CH_Basis.z; + let fragColor = vec4f(linear_srgb_vec(ACESFitted(max(col, vec3f(0.0)))), 1.0); + + //let c = textureLoad(myTexture, vec2(data.fragUV*d), 0).rgb; + //var fragColor = vec4f(pow( clamp(c, vec3(0.), vec3(1.)), vec3(1. / 2.2)), 1.); + //let fragColor = vec4f(ACES(sd.albedo), 1.0); + return fragColor; +// return textureLoad(texture_signed_distance, vec2(data.fragUV*iResolution), 0).rgba; +} diff --git a/src/scripts/light_buffer/common.wgsl b/src/scripts/light_buffer/common.wgsl new file mode 100644 index 0000000..220d997 --- /dev/null +++ b/src/scripts/light_buffer/common.wgsl @@ -0,0 +1,14 @@ +// -------------------------------------------------------------------------------------------- +const pi: f32 = 3.14159265359; +const tau: f32 = 6.28318530718; +const unit_circle_area:f32 = 2.0 * pi; + +// circular harmonics +// see also https://blackpawn.com/texts/ch/default.html +// and https://valdes.cc/articles/ch.html + +// Basis functions used here for circular harmonics +// 1 / sqrt(pi) of the basis function b1 = cos(phi) / sqrt(pi) +// 1 / sqrt(pi) of the basis function b2 = sin(phi) / sqrt(pi) +// 1 / sqrt(2*pi) of the basis function b0 = for 1 / sqrt(2*pi) +const CH_Basis = sqrt(vec3(2., 2., 1.0) / unit_circle_area); diff --git a/src/scripts/light_buffer/light.ts b/src/scripts/light_buffer/light.ts new file mode 100644 index 0000000..9170cfd --- /dev/null +++ b/src/scripts/light_buffer/light.ts @@ -0,0 +1,175 @@ +/* +Buffer A (Buffer A, keyboard, RGBA Noise Medium) (//Stores vars) +Buffer B (Buffer A, Buffer b, RGBA Noise Medium, CubeMap a) (Temporal ReSTIR) +Buffer C (Buffer A, Buffer B, RGBA Noise Medium, CubeMap a +Buffer D (Buffer A, Buffer B, Buffer C, Buffer D) (contains lightning, Temporal accumulation) +CubeMap A (Buffer A, Nothing , RGBA Noise Medium, CubeMap A) (scene storage) +Image.frag (Buffer A, Buffer C, Buffer D, CubeMap A) +*/ + +import {GPU} from "../webgpu/gpu"; +import {Buffer} from "../webgpu/buffer"; +import {GPUAbstractRunner, RunnerType} from "../AbstractGPURunner"; +import {Render} from "../render/render"; +import {LightScene} from "./scene/scene"; +import {ShowError} from "../ui"; + +export class LightPropagationBuffer extends GPUAbstractRunner { + width: number + height: number + + render: Render + scene: LightScene + + state: Buffer + + bind_group_layout: GPUBindGroupLayout + bind_group: GPUBindGroup + + bind_group_layout_buffer: GPUBindGroupLayout + bind_group_buffer: GPUBindGroup + + scene_bind_group_layout: GPUBindGroupLayout + scene_bind_group: GPUBindGroup + + pipeline_layout: GPUPipelineLayout + compute_pipeline: GPUComputePipeline + shader: GPUProgrammableStage + + stagingBuffer: Buffer + stagingData: Float32Array + + constructor() { + super() + this.width = GPU.viewport.width + this.height = GPU.viewport.height + } + + getType(): RunnerType { + return RunnerType.ASYNCANIM + } + + async Destroy() { + this.state.destroy() + } + + async Init() { + console.log("Create Texture") + + this.state = GPU.CreateStorageBuffer(this.width*this.height * (16*5) ) + + + this.stagingBuffer = GPU.CreateUniformBuffer(4 * 4) // must be a multiple of 16 bytes + this.stagingData = new Float32Array(4) + + this.scene = new LightScene(this.stagingBuffer) + try { + await this.scene.Init() + } catch (e) { + ShowError("Creation of Scene failed", e as Error) + throw e + } + + console.log("Create Render") + this.render = new Render( + [this.scene.emitter], + [this.state], + "scripts/light_buffer/common.wgsl", "scripts/light_buffer/aces-tone-mapping.wgsl") + await this.render.Init() + + this.shader = await GPU.CreateShaderFromURL("scripts/light_buffer/common.wgsl", "scripts/light_buffer/propagate.wgsl") + + this.bind_group_layout = GPU.device.createBindGroupLayout({ + label: "staging bind group layout", + entries: [{ + binding: 0, + visibility: GPUShaderStage.COMPUTE, + buffer: { + type: "uniform" + } + }] + }) + + this.bind_group = GPU.device.createBindGroup({ + layout: this.bind_group_layout, + entries: [{ + binding: 0, + resource: this.stagingBuffer.resource + }] + }) + + this.scene_bind_group_layout = GPU.device.createBindGroupLayout({ + label: "scene bind group layout", + entries: [ + { + binding: 0, + visibility: GPUShaderStage.COMPUTE, + texture: { + sampleType: "unfilterable-float", + viewDimension: "2d-array" + } + }] + }) + + this.scene_bind_group = GPU.device.createBindGroup({ + layout: this.scene_bind_group_layout, + entries: [{ + binding: 0, + resource: this.scene.emitter.textureView + }] + }) + + this.bind_group_layout_buffer = GPU.device.createBindGroupLayout({ + entries: [{ + binding: 0, + visibility: GPUShaderStage.COMPUTE, + buffer: { type: "storage" }, + }] + }) + + this.bind_group_buffer = GPU.device.createBindGroup({ + layout: this.bind_group_layout_buffer, + entries: [{ + binding: 0, + resource: this.state.resource + }] + }) + + this.pipeline_layout = GPU.device.createPipelineLayout({ + bindGroupLayouts: [this.bind_group_layout, this.scene_bind_group_layout, this.bind_group_layout_buffer] + }) + + this.compute_pipeline = GPU.device.createComputePipeline({ + layout: this.pipeline_layout, + compute: this.shader + }) + } + + GetCommandBuffer(): GPUCommandBuffer { + this.stagingData[0] = GPU.mouseCoordinate.x; // set iMouseX + this.stagingData[1] = GPU.mouseCoordinate.y; // set iMouseY + this.stagingData[2] = GPU.mouseCoordinate.wheel; + this.stagingData[3] += 1.; // increase iFrame + GPU.device.queue.writeBuffer(this.stagingBuffer.buffer, 0, this.stagingData) + + let encoder: GPUCommandEncoder = GPU.CreateCommandEncoder(); + for(let i = 0; i < 20; i++) { + let pass: GPUComputePassEncoder = encoder.beginComputePass(); + pass.setBindGroup(0, this.bind_group); + pass.setBindGroup(1, this.scene_bind_group); + pass.setBindGroup(2, this.bind_group_buffer); + pass.setPipeline(this.compute_pipeline); + pass.dispatchWorkgroups(this.width / 8, this.height / 8); + pass.end(); + } + return GPU.FinishCommandEncoder(encoder) + } + + async Run() { + GPU.device.queue.submit([this.scene.GetCommandBuffer(), this.GetCommandBuffer()]); + } + + Render() { + GPU.device.queue.submit([this.render.getCommandBuffer()]); + } +} diff --git a/src/scripts/light_buffer/propagate.wgsl b/src/scripts/light_buffer/propagate.wgsl new file mode 100644 index 0000000..6695caf --- /dev/null +++ b/src/scripts/light_buffer/propagate.wgsl @@ -0,0 +1,163 @@ +struct StagingBuffer { + iMouse: vec2f, + wheel: f32, + iFrame: f32 +}; + +struct ColorCH { + r: vec3f, + g: vec3f, + b: vec3f +}; + + +struct Cell { + // speherical harmonics for n=0 and n=1 + chr: vec3f, + chg: vec3f, + chb: vec3f, + + Em : vec3f, // emitted light + translucency: f32 +}; + +@group(0) @binding(0) var staging: StagingBuffer; +@group(1) @binding(0) var scene : texture_2d_array; +@group(2) @binding(0) var state: array; // this is used as both input and output + + +// propagate light from neighbor to this pixel +// n: normal of neighbor to center +// sa: solid angle of neighbor +fn propagate( + n: vec2f, + sa: f32, + F: ColorCH, // incoming light from neighbor + Em: ColorCH, // emitted light from neighbor + out: ptr) { + + // circular harmonic factors of light from neighbor to center + let dV = vec3f(n, 1.) * CH_Basis; + + // light hitting our interior cell wall + let L = max(vec3f(0.0), vec3f( + dot(F.r, dV), + dot(F.g, dV), + dot(F.b, dV)))*sa; + + // reflection + //let dRV = vec3f(-n, 1.) * CH_Basis; + + let ch = ColorCH(dV * L.r, dV * L.g, dV * L.b); + (*out).r += ch.r; + (*out).g += ch.g; + (*out).b += ch.b; +} + +fn solid_angle(a: vec2f, b: vec2f) -> f32 { + return acos(dot(normalize(a), normalize(b))); +} + +fn retrieveConstants(pn: vec2i, F: ptr, E: ptr) { + var idx = u32(pn.x + pn.y * 512); + + *F = ColorCH( + state[idx].chr, // incoming red light from neighbor as circular harmonics + state[idx].chg, // incoming green light from neighbor as circular harmonics + state[idx].chb, // incoming blue light from neighbor as circular harmonics + ); + /* + *E = ColorCH( + textureLoad(scene, pn, 0, 0).xyz, // emitted red light from neighbor as circular harmonics + textureLoad(scene, pn, 1, 0).xyz, // emitted green light from neighbor as circular harmonics + textureLoad(scene, pn, 2, 0).xyz, // emitted blue light from neighbor as circular harmonics + ); + */ +} + + // note that sa2 = (90° - sa1) / 2 + //const sa1: f32 = solid_angle(vec2f(1.5, -0.5), vec2(1.5, 0.5)); // ~53.13°, projecting to the right side of our pixel + //const sa2: f32 = solid_angle(vec2f(0.5, 0.5), vec2(1.5, 0.5)); // ~18.43°, projecting to the top/bottom side of our pixel + //const dn1: vec2f = normalize(vec2f(2., 1.0)); // normal to the center of the top side of our pixel + + // TODO: the comments are wrong + const sa1= 0.6435011087932845; // ~53.13°, projecting to the right side of our pixel + const sa2= 0.4636476090008066; // ~18.43°, projecting to the top/bottom side of our pixel + const dn1 = vec2f(0.8944271909999159, 0.4472135954999579); // normal to the center of the top side of our pixel + const dn0 = vec2f(0.8944271909999159, -0.4472135954999579); // normal to the center of the bottom side of our pixel + +fn lpv_kernel(p: vec2i, out: ptr) { + let Em = textureLoad(scene, p, 0, 0).xyz; // emitted rgb light as circular harmonics + let translucency = textureLoad(scene, p, 1, 0).w; + +/* + let d: i32 = 1; + let x: f32 = 2.0; + let sa1: f32 = solid_angle(vec2f(x, -1.0), vec2(x, 1.0)); // ~53.13°, projecting to the right side of our pixel + let sa2: f32 = solid_angle(vec2f(x - 1.0, 1.0), vec2(x, 1.0)); // ~18.43°, projecting to the top/bottom side of our pixel + // note that sa2 = (90° - sa1) / 2 + let dn1: vec2f = normalize(vec2f(x - 0.5, 1.0)); // normal to the center of the top side of our pixel + let dn0: vec2f = normalize(vec2f(x - 0.5, -1.0)); // normal to the center of the bottom side of our pixel +*/ + +/* +float sa1 = solid_angle(vec2(1.5, -0.5),vec2(1.5,0.5)); // ~53.13°, projecting to the right side of our pixel + float sa2 = solid_angle(vec2(0.5,0.5),vec2(1.5,0.5)); // ~18.43°, projecting to the top/bottom side of our pixel + vec2 dn1 = normalize(vec2(2., 1.0)); // normal to the center of the top side of our pixel + vec2 dn0 = normalize(vec2(2., -1.0)); // normal to the center of the bottom side of our pixel +*/ + + var pn : vec2i; + var F : ColorCH; + var E : ColorCH; + + pn = p + vec2i(-1, 0); + retrieveConstants(pn, &F, &E); + propagate(vec2f(1., 0.), sa1, F, E, out); + propagate(dn1, sa2, F, E, out); + propagate(dn0, sa2, F, E, out); + + pn = p + vec2i(1, 0); + retrieveConstants(pn, &F, &E); + propagate(vec2f(-1., 0.), sa1, F, E, out); + propagate(-dn0, sa2, F, E, out); + propagate(-dn1, sa2, F, E, out); + + pn = p + vec2i(0, -1); + retrieveConstants(pn, &F, &E); + propagate(vec2f(0., 1.), sa1, F, E, out); + propagate(dn1.yx, sa2, F, E, out); + propagate(dn0.yx, sa2, F, E, out); + + pn = p + vec2i(0, 1); + retrieveConstants(pn, &F, &E); + propagate(vec2f(0., -1.), sa1, F, E, out); + propagate(-dn1.yx, sa2, F, E, out); + propagate(-dn0.yx, sa2, F, E, out); + + (*out).r.z = (*out).r.z + Em.r; + (*out).g.z = (*out).g.z + Em.g; + (*out).b.z = (*out).b.z + Em.b; + + //var absorbed = ColorCH((*out).r * 1.-, (*out).g, (*out).b); + let absorbedr = (*out).r.z * (1.-translucency); + let absorbedg = (*out).g.z * (1.-translucency); + let absorbedb = (*out).b.z * (1.-translucency); + + (*out).r.z = (*out).r.z * (translucency) + absorbedr*0.8; + (*out).g.z = (*out).g.z * (translucency); + (*out).b.z = (*out).b.z * (translucency); +} + +@compute @workgroup_size(8, 8) +fn main(@builtin(global_invocation_id) global_id: vec3) { + var outch : ColorCH; + lpv_kernel(vec2i(global_id.xy), &outch); + + var idx = u32(global_id.x + global_id.y * 512); + state[idx].chr = outch.r; + state[idx].chg = outch.g; + state[idx].chb = outch.b; +} + + diff --git a/src/scripts/light_buffer/scene/scene.ts b/src/scripts/light_buffer/scene/scene.ts new file mode 100755 index 0000000..5a26a7e --- /dev/null +++ b/src/scripts/light_buffer/scene/scene.ts @@ -0,0 +1,136 @@ +import {GPU} from "../../webgpu/gpu"; +import {Texture} from "../../webgpu/texture"; +import {Buffer} from "../../webgpu/buffer"; +import {Raytrace} from "../../raytrace/raytrace"; +import {ShowError} from "../../ui"; +import {SDF} from "../../sdf/sdf"; + +export class LightScene { + width: number + height: number + + emitter: Texture + stagingBuffer: Buffer + + bind_group_layout: GPUBindGroupLayout + bind_group: GPUBindGroup + pipeline_layout: GPUPipelineLayout + compute_pipeline: GPUComputePipeline + shader: GPUProgrammableStage + + sdf: SDF + raytrace: Raytrace + //textureSignedDistance: Texture + + constructor(stagingBuffer : Buffer) { + this.width = GPU.viewport.width + this.height = GPU.viewport.height + this.stagingBuffer = stagingBuffer + } + + async Destroy() { + this.emitter.destroy() + //this.textureSignedDistance.destroy() + await this.sdf.Destroy() + await this.raytrace.Destroy() + } + + async Init() { + console.log("Init Scene") + let shader = await GPU.CreateShaderFromURL( + "scripts/light_buffer/common.wgsl", + "scripts/light_buffer/scene/scene.wgsl") + + // 0: color emitter circular harmonics, z-component + // 1: normal vector of the surface + this.emitter = GPU.CreateStorageTextureArray(this.width, this.height, 2, "rgba8unorm") + + this.raytrace = new Raytrace("fbm.wgsl") + try { + await this.raytrace.Init() + await this.raytrace.Run() + } catch (e) { + ShowError("Creation of FBM failed", e as Error) + throw e + } + + this.sdf = new SDF(this.raytrace.texturedest) + try { + await this.sdf.Init() + for(let i = 0; i < 256; i++) { + await this.sdf.Run() + } + } catch (e) { + ShowError("Creation of SDF failed", e as Error) + throw e + } + + this.bind_group_layout = GPU.device.createBindGroupLayout({ + label: "Scene Bind Group Layout", + entries: [{ + binding: 0, + storageTexture: { + access: "write-only", + format: this.emitter.format, + viewDimension: "2d-array" + }, + visibility: GPUShaderStage.COMPUTE + }, { + binding: 1, + buffer: { + type: "uniform" + }, + visibility: GPUShaderStage.COMPUTE, + }, { + binding: 2, + texture: { + sampleType: "unfilterable-float", + }, + visibility: GPUShaderStage.COMPUTE + }, ] + }); + + this.bind_group = GPU.device.createBindGroup({ + layout: this.bind_group_layout, + entries: [{ + binding: 0, + resource: this.emitter.textureView + }, { + binding: 1, + resource: this.stagingBuffer.resource + }, { + binding: 2, + resource: this.sdf.texturea.textureView + }] + }); + + this.pipeline_layout = GPU.device.createPipelineLayout({ + bindGroupLayouts: [this.bind_group_layout] + }); + + this.compute_pipeline = GPU.device.createComputePipeline({ + layout: this.pipeline_layout, + compute: shader + }); + } + + GetCommandBuffer() : GPUCommandBuffer { + let encoder: GPUCommandEncoder = GPU.CreateCommandEncoder(); + { + let pass: GPUComputePassEncoder = encoder.beginComputePass(); + pass.setBindGroup(0, this.bind_group); + pass.setPipeline(this.compute_pipeline); + pass.dispatchWorkgroups(this.width/8, this.height/8); + pass.end(); + } + //encoder.copyTextureToTexture({texture: this.velocitydest.texture}, {texture: this.velocity.texture}, [this.width, this.height, 1]); + + let command_buffer: GPUCommandBuffer = GPU.FinishCommandEncoder(encoder) + return command_buffer; + } + + async Run() { + GPU.device.queue.submit([this.GetCommandBuffer()]); + await GPU.device.queue.onSubmittedWorkDone() + } +} diff --git a/src/scripts/light_buffer/scene/scene.wgsl b/src/scripts/light_buffer/scene/scene.wgsl new file mode 100644 index 0000000..199c5e7 --- /dev/null +++ b/src/scripts/light_buffer/scene/scene.wgsl @@ -0,0 +1,61 @@ +struct StagingBuffer { + iMouse: vec2f, + wheel: f32, + iFrame: f32 +}; + + +var resolution: vec2; + +fn pixel2uv(p: vec2) -> vec2 { + var uv: vec2 = ((vec2(p) + 0.5) / resolution.xy)*2.0 - 1.0; + uv.x *= resolution.x/resolution.y; + return uv; +} + + +var mouse_pos = vec2(0.); +var mouse_wheel: f32 = 0.; + +fn sphere(p: vec2, r: f32) -> f32 { + return length(p) - r; +} + +@group(0) @binding(0) var scene : texture_storage_2d_array; +@group(0) @binding(1) var staging: StagingBuffer; +@group(0) @binding(2) var sdf : texture_2d; + +@compute @workgroup_size(8, 8) +fn main(@builtin(global_invocation_id) global_id: vec3) { + let iResolution = vec2f(textureDimensions(scene)); + resolution = iResolution.xy; + let p = vec2i(global_id.xy); + + mouse_pos = ((staging.iMouse.xy / iResolution.xy)*2.0 - 1.0) * vec2f(iResolution.x/iResolution.y, 1.0); + mouse_wheel = staging.wheel; + + let uv = pixel2uv(p); + + var ch = vec3f(0.); + + let d = sphere(uv - mouse_pos, (-mouse_wheel*0.005+0.05)); + if (d < 0) { + ch.r += 1.*CH_Basis.z; + ch.g += 1.*CH_Basis.z; + ch.b += 1.*CH_Basis.z; + } + + var translucency = f32(1.); + + let dT = textureLoad(sdf, p, 0).x/256.0; + if (dT < -0.05) { + translucency = 0.6; + } + + if (d < -0.02) { + translucency = 0.1; + } + + textureStore(scene, p, 0, vec4f(ch, 0.)); // emissive circular harmonics for rgb. + textureStore(scene, p, 1, vec4f(0., 0., 0., translucency)); // absorption +} diff --git a/src/scripts/light_monte_carlo_path_tracing/light.ts b/src/scripts/light_monte_carlo_path_tracing/light.ts index c84f278..316a065 100644 --- a/src/scripts/light_monte_carlo_path_tracing/light.ts +++ b/src/scripts/light_monte_carlo_path_tracing/light.ts @@ -65,6 +65,7 @@ export class LightMonteCarloPathTracing extends GPUAbstractRunner { console.log("Create Render") this.render = new Render( [this.textureSrc, this.scene.emitter], + [], "scripts/light_monte_carlo_path_tracing/aces-tone-mapping.wgsl") await this.render.Init() diff --git a/src/scripts/render/render.ts b/src/scripts/render/render.ts index 1993025..c4c430c 100755 --- a/src/scripts/render/render.ts +++ b/src/scripts/render/render.ts @@ -1,6 +1,7 @@ import {GPU} from "../webgpu/gpu"; import {Texture} from "../webgpu/texture"; import {GPUAbstractRunner, RunnerType} from "../AbstractGPURunner"; +import {Buffer} from "../webgpu/buffer"; export class Render extends GPUAbstractRunner { bind_group_layout: GPUBindGroupLayout @@ -8,12 +9,14 @@ export class Render extends GPUAbstractRunner { pipeline_layout: GPUPipelineLayout pipeline: GPURenderPipeline textures: Texture[] + buffers: Buffer[] fragmentShaderFilenames: string[] - constructor(textures: Texture[], ...fragmentShaderFilenames: string[]) { + constructor(textures: Texture[], buffers: Buffer[], ...fragmentShaderFilenames: string[]) { super(); this.fragmentShaderFilenames = fragmentShaderFilenames; this.textures = textures; + this.buffers = buffers; } override getType(): RunnerType { @@ -43,12 +46,13 @@ export class Render extends GPUAbstractRunner { let layoutEntries: GPUBindGroupLayoutEntry[] = []; let bindEntries: GPUBindGroupEntry[] = []; + let bindIdx = 0 for (let i = 0; i < this.textures.length; i++) { if (this.textures[i].depth > 1) { layoutEntries.push({ - binding: i, + binding: bindIdx, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: "unfilterable-float", @@ -57,7 +61,7 @@ export class Render extends GPUAbstractRunner { }) } else { layoutEntries.push({ - binding: i, + binding: bindIdx, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: "unfilterable-float" @@ -66,9 +70,25 @@ export class Render extends GPUAbstractRunner { } bindEntries.push({ - binding: i, + binding: bindIdx, resource: this.textures[i].textureView }) + bindIdx++ + } + + for (let i = 0; i < this.buffers.length; i++) { + layoutEntries.push( + { + binding: bindIdx, + visibility: GPUShaderStage.FRAGMENT, + buffer: {type: "storage"}, + }); + + bindEntries.push({ + binding: bindIdx, + resource: this.buffers[i].resource + }) + bindIdx++ } this.bind_group_layout = GPU.device.createBindGroupLayout({ diff --git a/src/scripts/sidebar.ts b/src/scripts/sidebar.ts index fa3bc00..9cf31a1 100644 --- a/src/scripts/sidebar.ts +++ b/src/scripts/sidebar.ts @@ -16,6 +16,7 @@ import {LightPropagation2} from "./light2/light"; import {GPURunner} from "./AbstractGPURunner"; import {SDF} from "./sdf/sdf"; import {LightMonteCarloPathTracing} from "./light_monte_carlo_path_tracing/light"; +import {LightPropagationBuffer} from "./light_buffer/light"; export async function ShowFeatures() { await HandleRunner(new Features()) @@ -33,7 +34,7 @@ export async function ShowBenchmark() { export async function ShowTexture() { let texture: Texture texture = await GPU.createTextureFromImage("scripts/render/Lenna.png") - await HandleRunner(new Render([texture])) + await HandleRunner(new Render([texture], [])) texture.destroy() } @@ -59,6 +60,11 @@ export async function ShowLightPropagation2() { await HandleRunner(new LightPropagation2()) } +export async function ShowLightPropagationBuffer() { + await HandleRunner(new LightPropagationBuffer()) +} + + async function RunOnce(runner: GPURunner) { try { await runner.Init() @@ -141,7 +147,12 @@ let toc: TOCEntry[] = [ title: "2D Light Propagation V2.0", elementName: "button_light_propagation2", func: ShowLightPropagation2 - }, + },/* + { + title: "2D Light Propagation V3.0", + elementName: "button_light_propagation_buffer", + func: ShowLightPropagationBuffer + },*/ { title: "2D Light By Monte Carlo Path Tracing", elementName: "button_light_path_tracing", diff --git a/src/scripts/webgpu/bufferFactory.ts b/src/scripts/webgpu/bufferFactory.ts index e7aa069..295cf9d 100644 --- a/src/scripts/webgpu/bufferFactory.ts +++ b/src/scripts/webgpu/bufferFactory.ts @@ -17,6 +17,22 @@ export class BufferFactory { return buffer; } + static createStorageBuffer(size: number) : Buffer { + let buffer = new Buffer() + buffer.size = size; + buffer.buffer = + GPU.device.createBuffer({ + usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC, + size: size, + mappedAtCreation: false + }); + buffer.resource = { + buffer: buffer.buffer + } + return buffer; + } + + static createCopyBuffer(size: number) : Buffer { let buffer = new Buffer() buffer.size = size; diff --git a/src/scripts/webgpu/gpu.ts b/src/scripts/webgpu/gpu.ts index 080f41c..3826764 100755 --- a/src/scripts/webgpu/gpu.ts +++ b/src/scripts/webgpu/gpu.ts @@ -215,6 +215,11 @@ export class GPU { return BufferFactory.createFromArrayBuffer(data) } + static CreateStorageBuffer(size: number): Buffer { + return BufferFactory.createStorageBuffer(size) + } + + static CreateUniformBuffer(size: number): Buffer { return BufferFactory.createUniformBuffer(size); }