Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions bun.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"version": "0.1.7",
"dependencies": {
"jimp": "1.6.0",
"typegpu": "^0.7.1",
"unplugin-typegpu": "^0.2.2",
"yoga-layout": "3.2.1",
},
"devDependencies": {
Expand Down Expand Up @@ -123,6 +125,8 @@

"@babel/preset-typescript": ["@babel/[email protected]", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ=="],

"@babel/standalone": ["@babel/[email protected]", "", {}, "sha512-VHmaaU23OkxShTtkwXlte7/uHDK8v55J9YLMqlucjnYujeB9YgrYCHU6LREqUegTVq+/KlLgjoUu8lbeI3XQPA=="],

"@babel/template": ["@babel/[email protected]", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="],

"@babel/traverse": ["@babel/[email protected]", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/types": "^7.28.2", "debug": "^4.3.1" } }, "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ=="],
Expand Down Expand Up @@ -191,6 +195,8 @@

"@jridgewell/gen-mapping": ["@jridgewell/[email protected]", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],

"@jridgewell/remapping": ["@jridgewell/[email protected]", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],

"@jridgewell/resolve-uri": ["@jridgewell/[email protected]", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],

"@jridgewell/sourcemap-codec": ["@jridgewell/[email protected]", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
Expand All @@ -199,6 +205,18 @@

"@opentui/core": ["@opentui/core@workspace:packages/core"],

"@opentui/core-darwin-arm64": ["@opentui/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LdEcuzG9I9jrz2snybqh4WAaEJY3oRbv1eh4fLaiWfr/P9YiSbsN1d30xJY0WUAe0vKvcj1yp/3SlyiyFqqzOg=="],

"@opentui/core-darwin-x64": ["@opentui/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-YuSpHznKbNJAbh3C6ghI/B+w3vNcbJWsgAeI+9BZ2bQfb4U4ThWfj2Wzfayek8VDYkkKJdpjqKEMFT5RD8Gosw=="],

"@opentui/core-linux-arm64": ["@opentui/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-djjd8RnDeKKyFIf1Sig7e0JnKq3qwRIDC1KFKQiR49spOGgCe9eeXxOWlNmx062WEslUk0Ic9FRPkpC8+04Kzw=="],

"@opentui/core-linux-x64": ["@opentui/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-8e8x3Lu/vcgIvWKqxWlV9qirkO1krNdIoct1doNNZNVOG2R/OzR/07zNf5H0gTkpjpL4R/TozLDC9jPTSEuLVw=="],

"@opentui/core-win32-arm64": ["@opentui/[email protected]", "", { "os": "win32", "cpu": "arm64" }, "sha512-2Vnrj2RPH7m6wI2VwBKO/bGEEcnnBQ/agQeHubKMoY3Wd5NOzXsBs/NAfFBpFunwNF+v6zgfnEjDQ9XU+zmbrQ=="],

"@opentui/core-win32-x64": ["@opentui/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-M9Xw6F3jmXF1+V7DHOPgJRypwp9Gb2ToZHg27/mN7sWkBDEDu9x2m4vdaQIoIEY26PqtcYjPOB5Tm0ESpEzZwQ=="],

"@opentui/react": ["@opentui/react@workspace:packages/react"],

"@opentui/solid": ["@opentui/solid@workspace:packages/solid"],
Expand All @@ -217,6 +235,8 @@

"@types/bun": ["@types/[email protected]", "", { "dependencies": { "bun-types": "1.2.20" } }, "sha512-dX3RGzQ8+KgmMw7CsW4xT5ITBSCrSbfHc36SNT31EOUg/LA9JWq0VDdEXDRSe1InVWpd2yLUM1FUF/kEOyTzYA=="],

"@types/estree": ["@types/[email protected]", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],

"@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow=="],

"@types/react": ["@types/[email protected]", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg=="],
Expand All @@ -233,6 +253,8 @@

"abort-controller": ["[email protected]", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="],

"acorn": ["[email protected]", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],

"any-base": ["[email protected]", "", {}, "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg=="],

"await-to-js": ["[email protected]", "", {}, "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g=="],
Expand Down Expand Up @@ -277,12 +299,16 @@

"debug": ["[email protected]", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],

"defu": ["[email protected]", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],

"electron-to-chromium": ["[email protected]", "", {}, "sha512-uz4i0vLhfm6dLZWbz/iH88KNDV+ivj5+2SA+utpgjKaj9Q0iDLuwk6Idhe9BTxciHudyx6IvTvijhkPvFGUQ0g=="],

"entities": ["[email protected]", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],

"escalade": ["[email protected]", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],

"estree-walker": ["[email protected]", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],

"event-target-shim": ["[email protected]", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="],

"events": ["[email protected]", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
Expand Down Expand Up @@ -331,6 +357,10 @@

"lru-cache": ["[email protected]", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],

"magic-string": ["[email protected]", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],

"magic-string-ast": ["[email protected]", "", { "dependencies": { "magic-string": "^0.30.17" } }, "sha512-8ngQgLhcT0t3YBdn9CGkZqCYlvwW9pm7aWJwd7AxseVWf1RU8ZHCQvG1mt3N5vvUme+pXTcHB8G/7fE666U8Vw=="],

"meshoptimizer": ["[email protected]", "", {}, "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw=="],

"mime": ["[email protected]", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
Expand Down Expand Up @@ -367,10 +397,14 @@

"path-scurry": ["[email protected]", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],

"pathe": ["[email protected]", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],

"peek-readable": ["[email protected]", "", {}, "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg=="],

"picocolors": ["[email protected]", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],

"picomatch": ["[email protected]", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],

"pixelmatch": ["[email protected]", "", { "dependencies": { "pngjs": "^6.0.0" }, "bin": { "pixelmatch": "bin/pixelmatch" } }, "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q=="],

"pkg-up": ["[email protected]", "", { "dependencies": { "find-up": "^3.0.0" } }, "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA=="],
Expand Down Expand Up @@ -423,18 +457,32 @@

"tinycolor2": ["[email protected]", "", {}, "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="],

"tinyest": ["[email protected]", "", {}, "sha512-YNHlB8BOXgW6RPzrfqqAkgyY9xj33sjXJcJlOl3MwY0BXXx26m3JUqf5yV8iBdwJPNe51DmxypR9Zbbd266biQ=="],

"tinyest-for-wgsl": ["[email protected]", "", { "dependencies": { "tinyest": "~0.1.1" } }, "sha512-yJ49SoJIpEi4ADsBVNE54GVJ5JZMIAKNkRueeNpYhIiq0z1Nn9THJNMNP1b9HI0VQt7LzCrxT0ZP29muiUtcRg=="],

"token-types": ["[email protected]", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ=="],

"typed-binary": ["[email protected]", "", {}, "sha512-HT3pIBM2njCZUmeczDaQUUErGiM6GXFCqMsHegE12HCoBtvHCkfR10JJni0TeGOTnLilTd6YFyj+YhflqQDrDQ=="],

"typegpu": ["[email protected]", "", { "dependencies": { "tinyest": "~0.1.1", "typed-binary": "^4.3.1" } }, "sha512-PyP/ZRsX8lCX27fNzBE5TjwxC8Vj88RcLlCv4VXg5sVd6gBuiPZTJQoC5HR15hjTJoRAfayT/TXQ4phWOkA/aA=="],

"typescript": ["[email protected]", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],

"undici-types": ["[email protected]", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="],

"unplugin": ["[email protected]", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-+/MdXl8bLTXI2lJF22gUBeCFqZruEpL/oM9f8wxCuKh9+Mw9qeul3gTqgbKpMeOFlusCzc0s7x2Kax2xKW+FQg=="],

"unplugin-typegpu": ["[email protected]", "", { "dependencies": { "@babel/standalone": "^7.27.0", "defu": "^6.1.4", "estree-walker": "^3.0.3", "magic-string-ast": "^1.0.0", "pathe": "^2.0.3", "picomatch": "^4.0.3", "tinyest": "~0.1.1", "tinyest-for-wgsl": "~0.1.2", "unplugin": "^2.3.5" }, "peerDependencies": { "typegpu": "^0.7.0" } }, "sha512-5pbwv0cTMRMxRCQXEPAMUsUoAKMQsz2B4zlhpRRHNy3qtMk+rP3Uxe/5zZUtr2yAASCVO2iciblH5HqcUoijjQ=="],

"update-browserslist-db": ["[email protected]", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="],

"utif2": ["[email protected]", "", { "dependencies": { "pako": "^1.0.11" } }, "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w=="],

"validate-html-nesting": ["[email protected]", "", {}, "sha512-kdkWdCl6eCeLlRShJKbjVOU2kFKxMF8Ghu50n+crEoyx+VKm3FxAxF9z4DCy6+bbTOqNW0+jcIYRnjoIRzigRw=="],

"webpack-virtual-modules": ["[email protected]", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="],

"xml-parse-from-string": ["[email protected]", "", {}, "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g=="],

"xml2js": ["[email protected]", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="],
Expand Down
1 change: 1 addition & 0 deletions packages/core/bunfig.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
preload = ["./preload.ts"]
4 changes: 3 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@
},
"dependencies": {
"jimp": "1.6.0",
"yoga-layout": "3.2.1"
"yoga-layout": "3.2.1",
"typegpu": "^0.7.1",
"unplugin-typegpu": "^0.2.2"
},
"optionalDependencies": {
"@dimforge/rapier2d-simd-compat": "^0.17.3",
Expand Down
4 changes: 4 additions & 0 deletions packages/core/preload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { plugin } from "bun"
import typegpu from "unplugin-typegpu/bun"

plugin(typegpu({ include: /\.ts$/ }))
104 changes: 28 additions & 76 deletions packages/core/src/3d/canvas.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { GPUCanvasContextMock } from "bun-webgpu"
import { tgpu, type TgpuBuffer, type TgpuComputePipeline, type TgpuRoot, type UniformFlag } from "typegpu"
import { RGBA } from "../types"
import { SuperSampleType } from "./WGPURenderer"
import type { OptimizedBuffer } from "../buffer"
import { createSuperSamplingComputeShader, layout as superSamplingLayout, SuperSamplingParams } from './shaders/supersampling'
import { toArrayBuffer } from "bun:ffi"
import { Jimp } from "jimp"

// @ts-ignore
import shaderTemplate from "./shaders/supersampling.wgsl" with { type: "text" }

const WORKGROUP_SIZE = 4
const SUPERSAMPLING_COMPUTE_SHADER = shaderTemplate.replace(/\${WORKGROUP_SIZE}/g, WORKGROUP_SIZE.toString())
const SUPERSAMPLING_COMPUTE_SHADER = createSuperSamplingComputeShader(WORKGROUP_SIZE)

export enum SuperSampleAlgorithm {
STANDARD = 0,
Expand All @@ -18,6 +17,7 @@ export enum SuperSampleAlgorithm {

export class CLICanvas {
private device: GPUDevice
private root: TgpuRoot
private readbackBuffer: GPUBuffer | null = null
private width: number
private height: number
Expand All @@ -28,10 +28,9 @@ export class CLICanvas {
public superSample: SuperSampleType = SuperSampleType.GPU

// Compute shader super sampling
private computePipeline: GPUComputePipeline | null = null
private computeBindGroupLayout: GPUBindGroupLayout | null = null
private computePipeline: TgpuComputePipeline | null = null
private computeOutputBuffer: GPUBuffer | null = null
private computeParamsBuffer: GPUBuffer | null = null
private computeParamsBuffer: TgpuBuffer<typeof SuperSamplingParams> & UniformFlag | null = null
private computeReadbackBuffer: GPUBuffer | null = null
private updateScheduled: boolean = false
private screenshotGPUBuffer: GPUBuffer | null = null
Expand All @@ -45,6 +44,7 @@ export class CLICanvas {
sampleAlgo: SuperSampleAlgorithm = SuperSampleAlgorithm.STANDARD,
) {
this.device = device
this.root = tgpu.initFromDevice({ device })
this.width = width
this.height = height
this.superSample = superSample
Expand Down Expand Up @@ -163,52 +163,14 @@ export class CLICanvas {
private async initComputePipeline(): Promise<void> {
if (this.computePipeline) return

const shaderModule = this.device.createShaderModule({
label: "SuperSampling Compute Shader",
code: SUPERSAMPLING_COMPUTE_SHADER,
})

this.computeBindGroupLayout = this.device.createBindGroupLayout({
label: "SuperSampling Bind Group Layout",
entries: [
{
binding: 0,
visibility: GPUShaderStage.COMPUTE,
texture: { sampleType: "float", viewDimension: "2d" },
},
{
binding: 1,
visibility: GPUShaderStage.COMPUTE,
buffer: { type: "storage" },
},
{
binding: 2,
visibility: GPUShaderStage.COMPUTE,
buffer: { type: "uniform" },
},
],
})
this.computePipeline = this.root['~unstable']
.withCompute(SUPERSAMPLING_COMPUTE_SHADER)
.createPipeline()

const pipelineLayout = this.device.createPipelineLayout({
label: "SuperSampling Pipeline Layout",
bindGroupLayouts: [this.computeBindGroupLayout],
})

this.computePipeline = this.device.createComputePipeline({
label: "SuperSampling Compute Pipeline",
layout: pipelineLayout,
compute: {
module: shaderModule,
entryPoint: "main",
},
})

// Create uniform buffer for parameters (8 bytes - 2 u32s: width, height)
this.computeParamsBuffer = this.device.createBuffer({
label: "SuperSampling Params Buffer",
size: 16,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
})
// Create uniform buffer for parameters
this.computeParamsBuffer = this.root.createBuffer(SuperSamplingParams)
.$usage('uniform')
.$name("SuperSampling Params Buffer")

this.updateComputeParams()
}
Expand All @@ -218,14 +180,11 @@ export class CLICanvas {

// Update uniform buffer with parameters
// Note: this.width/height are render dimensions (2x terminal size for super sampling)
const paramsData = new ArrayBuffer(16)
const uint32View = new Uint32Array(paramsData)

uint32View[0] = this.width
uint32View[1] = this.height
uint32View[2] = this.superSampleAlgorithm

this.device.queue.writeBuffer(this.computeParamsBuffer, 0, paramsData)
this.computeParamsBuffer.write({
width: this.width,
height: this.height,
sampleAlgo: this.superSampleAlgorithm,
})
}

private scheduleUpdateComputeBuffers(): void {
Expand Down Expand Up @@ -278,7 +237,6 @@ export class CLICanvas {

if (
!this.computePipeline ||
!this.computeBindGroupLayout ||
!this.computeOutputBuffer ||
!this.computeParamsBuffer
) {
Expand All @@ -290,30 +248,24 @@ export class CLICanvas {
label: "SuperSampling Input Texture View",
})

const bindGroup = this.device.createBindGroup({
label: "SuperSampling Bind Group",
layout: this.computeBindGroupLayout,
entries: [
{ binding: 0, resource: textureView },
{ binding: 1, resource: { buffer: this.computeOutputBuffer } },
{ binding: 2, resource: { buffer: this.computeParamsBuffer } },
],
const bindGroup = this.root.createBindGroup(superSamplingLayout, {
inputTexture: textureView,
output: this.computeOutputBuffer,
params: this.computeParamsBuffer,
})

const commandEncoder = this.device.createCommandEncoder({ label: "SuperSampling Command Encoder" })
const computePass = commandEncoder.beginComputePass({ label: "SuperSampling Compute Pass" })
computePass.setPipeline(this.computePipeline)
computePass.setBindGroup(0, bindGroup)

// Must match WGSL calculation exactly: (params.width + 1u) / 2u
const terminalWidthCells = Math.floor((this.width + 1) / 2)
const terminalHeightCells = Math.floor((this.height + 1) / 2)
const dispatchX = Math.ceil(terminalWidthCells / WORKGROUP_SIZE)
const dispatchY = Math.ceil(terminalHeightCells / WORKGROUP_SIZE)

computePass.dispatchWorkgroups(dispatchX, dispatchY, 1)
computePass.end()
this.computePipeline
.with(superSamplingLayout, bindGroup)
.dispatchWorkgroups(dispatchX, dispatchY)
this.root["~unstable"].flush()

const commandEncoder = this.device.createCommandEncoder({ label: "SuperSampling Command Encoder" })
commandEncoder.copyBufferToBuffer(
this.computeOutputBuffer,
0,
Expand Down
Loading