diff --git a/build/tools/serve.js b/build/tools/serve.js new file mode 100644 index 0000000..377844a --- /dev/null +++ b/build/tools/serve.js @@ -0,0 +1,16 @@ +import {spawn} from 'child_process'; + +spawn('npm', [ + 'run', + 'watch', +], { + shell: true, + stdio: 'inherit', +}); + +spawn('./node_modules/.bin/servez', [ +], { + shell: true, + stdio: 'inherit', +}); + diff --git a/package-lock.json b/package-lock.json index 82595b1..0ac46fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "webgpu-debug-helper", "version": "0.0.1", "license": "MIT", + "dependencies": { + "webgpu-utils": "^1.3.0" + }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-terser": "^0.4.3", @@ -26,6 +29,7 @@ "mocha": "^10.2.0", "puppeteer": "^21.0.1", "rollup": "^3.27.1", + "servez": "^2.1.2", "tslib": "^2.6.1", "typedoc": "^0.24.8", "typescript": "^5.1.6", @@ -587,11 +591,19 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", "dev": true, - "optional": true, "dependencies": { "undici-types": "~5.26.4" } }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/resolve": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", @@ -994,6 +1006,24 @@ } ] }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dev": true, + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "node_modules/basic-ftp": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.4.tgz", @@ -1003,6 +1033,12 @@ "node": ">=10.0.0" } }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -1271,6 +1307,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -1319,6 +1364,19 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "dev": true }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cosmiconfig": { "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", @@ -3120,6 +3178,15 @@ } } }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -3129,6 +3196,15 @@ "node": ">=0.10.0" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", @@ -3665,6 +3741,25 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "node_modules/secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -3746,6 +3841,84 @@ "randombytes": "^2.1.0" } }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -3761,6 +3934,52 @@ "node": ">= 0.8.0" } }, + "node_modules/server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==", + "dev": true + }, + "node_modules/servez": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/servez/-/servez-2.1.2.tgz", + "integrity": "sha512-uJ/GlvogUfe52p9E5p9maEMQzycEMiz1doWkW8rke33WezHQ1P6/xPBqerOoeK9ze24Am1vJey7j/ddtySJTwg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "color-support": "^1.1.3", + "commander": "^11.0.0", + "servez-lib": "^2.8.1" + }, + "bin": { + "servez": "bin/servez" + } + }, + "node_modules/servez-lib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/servez-lib/-/servez-lib-2.8.1.tgz", + "integrity": "sha512-Wg/hvTxBPJ0ZqlQKTDktMDEAi/V5/wXdEaj4/O6SM1ZmqwWQoHDw0Yyg7l/G91znMQOCkyEdfAFPasOpjQWbNg==", + "dev": true, + "dependencies": { + "basic-auth": "^2.0.1", + "cors": "^2.8.5", + "debug": "^4.3.4", + "express": "^4.18.2", + "secure-compare": "^3.0.1", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "server-destroy": "^1.0.1" + } + }, + "node_modules/servez/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, "node_modules/set-function-length": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", @@ -4200,8 +4419,7 @@ "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true, - "optional": true + "dev": true }, "node_modules/universalify": { "version": "0.1.2", @@ -4266,6 +4484,11 @@ "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", "dev": true }, + "node_modules/webgpu-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/webgpu-utils/-/webgpu-utils-1.3.0.tgz", + "integrity": "sha512-v8Kx6uwZ3BLkdiMnaO13zstwFCmEhLhadJsX0sMpWaiW8/Gu+R4AxkV7l1EEt8whM7lJeET1YeP5rIZaJ/sZoA==" + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/package.json b/package.json index 32c1211..4acf535 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "lint": "eslint \"src/**/*.{js,ts,tsx}\"", "pre-push": "npm run lint && npm run build && npm run test", "watch": "rollup -c -w", - "start": "rollup -c rollup.config.js -w", + "start": "node build/tools/serve.js", "test": "node test/puppeteer.js" }, "repository": { @@ -56,9 +56,13 @@ "mocha": "^10.2.0", "puppeteer": "^21.0.1", "rollup": "^3.27.1", + "servez": "^2.1.2", "tslib": "^2.6.1", "typedoc": "^0.24.8", "typescript": "^5.1.6", "wgsl_reflect": "github:brendan-duncan/wgsl_reflect#713ad94" + }, + "dependencies": { + "webgpu-utils": "^1.3.0" } } diff --git a/src/webgpu-debug-helper.ts b/src/webgpu-debug-helper.ts index a269ee5..f624521 100644 --- a/src/webgpu-debug-helper.ts +++ b/src/webgpu-debug-helper.ts @@ -3,6 +3,12 @@ if (typeof GPUDevice !== 'undefined') { const origPushErrorScope = GPUDevice.prototype.pushErrorScope; const origPopErrorScope = GPUDevice.prototype.popErrorScope; + function assert(condition: boolean, msg?: string | (() => string)): asserts condition { + if (!condition) { + emitError(msg ? (typeof msg === 'string' ? msg : msg()) : ''); + } + } + function getFilterForGPUError(error: GPUError): GPUErrorFilter { if (error instanceof GPUValidationError) { return 'validation'; @@ -97,4 +103,89 @@ if (typeof GPUDevice !== 'undefined') { return device; } })(GPUAdapter.prototype.requestDevice); + + function wrapFunctionBefore any>>( + API: { prototype: T }, + fnName: K, fn: (...args: Parameters) => void) { + const origFn = API.prototype[fnName]; + API.prototype[fnName] = function (this: T, ...args: any) { + fn.call(this, ...args); + return origFn.call(this, ...args); + } as any; + } + + function wrapFunctionAfter any>>( + API: { prototype: T }, + fnName: K, fn: (obj: ReturnType,...args: Parameters) => void) { + const origFn = API.prototype[fnName]; + API.prototype[fnName] = function (this: T, ...args: any) { + const result = origFn.call(this, ...args); + fn.call(this, result, ...args); + return result; + } as any; + } + + type LabeledObject = GPUTexture | GPUTextureView | GPURenderPassEncoder | GPUCommandEncoder; + + function emitError(msg: string, objs: LabeledObject[] = []) { + throw new Error(`${msg}\n${(objs).map(o => `[${o.constructor.name}]${o.label}`).join('\n')}`); + } + + type RenderPassInfo = { + targetWidth: number, + targetHeight: number, + }; + + const textureViewToTexture = new WeakMap(); + const renderPassToPassInfoMap = new WeakMap(); + + wrapFunctionAfter(GPUTexture, 'createView', function(this: GPUTexture, view: GPUTextureView, desc?: GPUTextureViewDescriptor) { + textureViewToTexture.set(view, this); + }); + + wrapFunctionAfter(GPUCommandEncoder, 'beginRenderPass', function(this: GPUCommandEncoder, passEncoder: GPURenderPassEncoder, desc: GPURenderPassDescriptor) { + let targetWidth: number | undefined; + let targetHeight: number | undefined; + + const addView = (attachment: GPURenderPassColorAttachment | GPURenderPassDepthStencilAttachment | null | undefined) => { + if (!attachment) { + return; + } + const {view} = attachment; + const texture = textureViewToTexture.get(view)!; + const {width, height} = texture; + if (targetWidth === undefined) { + targetWidth = width; + targetHeight = height; + } else if (targetWidth !== width || targetHeight !== height) { + emitError('attachments are not all the same width and height', [view, texture, passEncoder, this]); + } + } + + for (const colorAttachment of desc.colorAttachments || []) { + addView(colorAttachment); + } + + addView(desc.depthStencilAttachment); + + assert(targetWidth !== undefined); + assert(targetHeight !== undefined); + + renderPassToPassInfoMap.set(passEncoder, { + targetWidth, + targetHeight, + }); + }); + + wrapFunctionBefore(GPURenderPassEncoder, 'setViewport', function(this: GPURenderPassEncoder, x: number, y: number, width: number, height: number, minDepth: number, maxDepth: number) { + const { + targetWidth, + targetHeight, + } = renderPassToPassInfoMap.get(this)!; + assert(x >= 0, 'x < 0'); + assert(y >= 0, 'y < 0'); + assert(x + width <= targetWidth, 'x + width > texture.width'); + assert(y + height <= targetHeight, 'y + height > texture.height'); + }); + } \ No newline at end of file diff --git a/test/index.js b/test/index.js index 68b066d..f13473f 100644 --- a/test/index.js +++ b/test/index.js @@ -1,5 +1,5 @@ /* global mocha */ -import './tests/webgpu-debug-helper.js'; +import './tests/webgpu-debug-helper-tests.js'; const settings = Object.fromEntries(new URLSearchParams(window.location.search).entries()); if (settings.reporter) { diff --git a/test/tests/webgpu-debug-helper-tests.js b/test/tests/webgpu-debug-helper-tests.js new file mode 100644 index 0000000..963e152 --- /dev/null +++ b/test/tests/webgpu-debug-helper-tests.js @@ -0,0 +1,82 @@ +import '../../dist/0.x/webgpu-debug-helper.js'; + +import { + assertEqual, + assertFalsy, + assertIsArray, + assertInstanceOf, + assertStrictEqual, + assertStrictNotEqual, + assertTruthy, +} from '../assert.js'; +import {describe, it, beforeEach, afterEach} from '../mocha-support.js'; + +async function createRenderPass() { + const adapter = await navigator.gpu.requestAdapter(); + const device = await adapter.requestDevice(); + const texture = device.createTexture({ + size: [2, 3], + usage: GPUTextureUsage.RENDER_ATTACHMENT, + format: 'rgba8unorm', + }); + const encoder = device.createCommandEncoder(); + const pass = encoder.beginRenderPass({ + colorAttachments: [{ + view: texture.createView(), + clearColor: [0, 0, 0, 0], + loadOp: 'clear', + storeOp: 'store', + }], + }); + return pass; +} + +function expectValidationError(expectError, fn) { + let error = false; + try { + fn(); + } catch (e) { + error = e; + } + if (expectError) { + if (!error) { + throw new Error('expected error, no error thrown'); + } + } else { + if (error) { + throw error; + } + } +} + +describe('test webgpu-debug-helper', () => { + + describe('test render pass encoder', () => { + + describe('should generate error on setViewport', () => { + + const tests = [ + { success: true, args: [0, 0, 2, 3, 0, 1], desc: 'valid' }, + { success: false, args: [-1, 0, 1, 1, 0, 1], desc: 'x < 0' }, + { success: false, args: [ 0, -1, 1, 1, 0, 1], desc: 'y < 0' }, + { success: false, args: [ 0, 0, 3, 1, 0, 1], desc: 'x + width > targetWidth' }, + { success: false, args: [ 1, 0, 2, 1, 0, 1], desc: 'x + width > targetWidth' }, + { success: false, args: [ 0, 0, 1, 4, 0, 1], desc: 'y + height > targetHeight' }, + { success: false, args: [ 0, 1, 1, 3, 0, 1], desc: 'y + height > targetHeight' }, + ]; + + for (let {success, args, desc} of tests) { + it(desc, async () => { + const pass = await createRenderPass(); + expectValidationError(!success, () => { + pass.setViewport(...args); + }); + }); + + } + + }); + + }); + +}); diff --git a/test/tests/webgpu-debug-helper.js b/test/tests/webgpu-debug-helper.js deleted file mode 100644 index f649759..0000000 --- a/test/tests/webgpu-debug-helper.js +++ /dev/null @@ -1,43 +0,0 @@ -import {mat3, mat4, quat, utils} from '../../dist/2.x/wgpu-matrix.module.js'; - -import { - assertEqual, - assertFalsy, - assertIsArray, - assertInstanceOf, - assertStrictEqual, - assertStrictNotEqual, - assertTruthy, -} from '../assert.js'; -import {describe, it, before} from '../mocha-support.js'; - -function assertMat3Equal(a, b) { - if (!mat3.equals(a, b)) { - throw new Error(`${a} !== ${b}`); - } -} - -function assertMat3EqualApproximately(a, b) { - if (!mat3.equalsApproximately(a, b)) { - throw new Error(`${a} !== ${b}`); - } -} - -describe('test webgpu-debug-helper', () => { - let savedFuncEntries; - - beforeEach(() => { - savedFuncEntries = saveFunctionsOfClasses([ - GPUDevice, - ]); - }); - - afterEach(() => { - restoreFunctionsOfClasses(savedFuncEntries); - }); - - it('should catch pass.ooo', () => { - - }); - -});