From 2c4efff6841a3367310154b279c7e41b1c7696f0 Mon Sep 17 00:00:00 2001 From: Sebastian Sanabria Date: Thu, 8 Jun 2023 18:40:34 -0600 Subject: [PATCH 1/9] Update absulit.points.module.js - bindingIndex has to increase because if not `addBindingTexture` can only add one, so this allows for multiple calls to `addBindingTexture` --- src/absulit.points.module.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/absulit.points.module.js b/src/absulit.points.module.js index f2588d7a..35df7786 100644 --- a/src/absulit.points.module.js +++ b/src/absulit.points.module.js @@ -1334,7 +1334,7 @@ export default class Points { entries.push( { label: 'binding texture 2', - binding: bindingIndex, // this does not increase, must match the previous block + binding: bindingIndex++, resource: bindingTexture.texture.createView(), type: { name: 'texture', From 4cd0182f219d09a91da8f0486c877d3d58b0360d Mon Sep 17 00:00:00 2001 From: Sebastian Sanabria Date: Thu, 8 Jun 2023 19:22:49 -0600 Subject: [PATCH 2/9] Update main.js - button to download image as png --- examples/main.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/main.js b/examples/main.js index 6f098d49..05404347 100644 --- a/examples/main.js +++ b/examples/main.js @@ -41,7 +41,7 @@ gui.add(stats2, 'visible').name('Show Stats').onChange(value => setStatsVisibili let isFullscreenData = { 'isFullscreen': false }; let fullscreenCheck = gui.add(isFullscreenData, 'isFullscreen').name('Fullscreen').onChange(value => points.fullscreen = value); -document.addEventListener("fullscreenchange", e => { +document.addEventListener('fullscreenchange', e => { let isFullscreen = window.innerWidth == screen.width && window.innerHeight == screen.height; isFullscreenData.isFullscreen = isFullscreen; fullscreenCheck.updateDisplay(); @@ -148,6 +148,13 @@ const recordingOptions = [ started: false, controller: null }, + { + nameStopped: 'Download PNG Image', + fn: function (e) { + let image = document.getElementById('gl-canvas').toDataURL().replace('image/png', 'image/octet-stream'); + window.location.href = image; + }, + }, ]; recordingOptions.forEach(recordingOption => { From d07bf5a7f1cda1b88de7b2bec36a8053cf4ee471 Mon Sep 17 00:00:00 2001 From: Sebastian Sanabria Date: Sat, 10 Jun 2023 18:30:24 -0600 Subject: [PATCH 3/9] fix to fullscreen not working with js console open - If the console is open it detect different dimensions, but if we first assign the fit window method it works - We remember fitWindow value and re assign it after we exit fullscreen --- src/absulit.points.module.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/absulit.points.module.js b/src/absulit.points.module.js index 35df7786..1db32a55 100644 --- a/src/absulit.points.module.js +++ b/src/absulit.points.module.js @@ -259,16 +259,20 @@ export default class Points { window.addEventListener('resize', this._resizeCanvasToFitWindow, false); document.addEventListener("fullscreenchange", e => { - let isFullscreen = window.innerWidth == screen.width && window.innerHeight == screen.height; + let isFullscreen = !!document.fullscreenElement; this._fullscreen = isFullscreen; if (!isFullscreen && !this._fitWindow) { this._resizeCanvasToDefault(); } + if (!isFullscreen) { + this.fitWindow = this._lastFitWindow; + } }); } this._fullscreen = false; this._fitWindow = false; + this._lastFitWindow = false; // _readStorage should only be read once @@ -1603,6 +1607,8 @@ export default class Points { set fullscreen(value) { if (value) { + this._lastFitWindow = this._fitWindow; + this.fitWindow = value; this._canvas.requestFullscreen().catch(err => { throw `Error attempting to enable fullscreen mode: ${err.message} (${err.name})`; }); From 9fe269670f330d4c1640957a3db0f884b7b95881 Mon Sep 17 00:00:00 2001 From: Sebastian Sanabria Date: Sat, 10 Jun 2023 19:01:25 -0600 Subject: [PATCH 4/9] Simplified circleblur compute - with better workgroups --- examples/circleblur/compute.js | 47 ++++++++++++---------------------- examples/circleblur/index.js | 8 +++--- 2 files changed, 21 insertions(+), 34 deletions(-) diff --git a/examples/circleblur/compute.js b/examples/circleblur/compute.js index dbfcdd45..e69a0711 100644 --- a/examples/circleblur/compute.js +++ b/examples/circleblur/compute.js @@ -4,7 +4,7 @@ const compute = /*wgsl*/` ${clearMix} -const workgroupSize = 8; +const workgroupSize = 1; //'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup' @@ -15,42 +15,27 @@ fn main( @builtin(local_invocation_id) LocalInvocationID: vec3 ) { - let filterDim = 128u; - let blockDim = 128u; - let flipValue = 0u; + // let filterDim = 128u; + // let blockDim = 128u; + // let flipValue = 0u; - let filterOffset : u32 = (filterDim - 1u) / 2u; - let dims : vec2 = textureDimensions(feedbackTexture, 0); + // let filterOffset : u32 = (filterDim - 1u) / 2u; - let baseIndex = vec2( - WorkGroupID.xy * vec2(blockDim, 4u) + - LocalInvocationID.xy * vec2(4u, 1u) - ) - vec2(i32(filterOffset), 0); + // let baseIndex = vec2( + // WorkGroupID.xy * vec2(blockDim, 4u) + + // LocalInvocationID.xy * vec2(4u, 1u) + // ) - vec2(i32(filterOffset), 0); // ---------------------------------------------- - let numColumns:f32 = f32(dims.x); - let numRows:f32 = f32(dims.y); - let numColumnsPiece:i32 = i32(numColumns / f32(workgroupSize)); - let numRowsPiece:i32 = i32(numRows / f32(workgroupSize)); - for (var indexColumns:i32 = 0; indexColumns < numColumnsPiece; indexColumns++) { - let x:f32 = f32(WorkGroupID.x) * f32(numColumnsPiece) + f32(indexColumns); - let ux = u32(x); - let nx = x / numColumns; - for (var indexRows:i32 = 0; indexRows < numRowsPiece; indexRows++) { - - let y:f32 = f32(WorkGroupID.y) * f32(numRowsPiece) + f32(indexRows); - let uy = u32(y); - let ny = y / numRows; - - var rgba = textureSampleLevel(feedbackTexture,feedbackSampler, vec2(x,y), 0.0); - - rgba = clearMix(rgba, 1.01) + vec4(1.,0.,0., .5); - - textureStore(outputTex, vec2(ux,uy), rgba); - } - } + var rgba = textureSampleLevel( + feedbackTexture,feedbackSampler, + vec2(f32(GlobalId.x), f32(GlobalId.y)), + 0.0 + ); + rgba = clearMix(rgba, 1.01) + vec4(1.,0.,0., .5); + textureStore(outputTex, GlobalId.xy, rgba); } `; diff --git a/examples/circleblur/index.js b/examples/circleblur/index.js index a6e8d4d4..d5088067 100644 --- a/examples/circleblur/index.js +++ b/examples/circleblur/index.js @@ -1,10 +1,12 @@ import vert from './vert.js'; import compute from './compute.js'; import frag from './frag.js'; +import { RenderPass } from '../../src/absulit.points.module.js'; const circleblur = { - vert, - compute, - frag, + renderPasses: [ + new RenderPass(null, null, compute, 800, 800, 1), + new RenderPass(vert, frag, null, 8, 1, 1) + ], init: async points => { points.addSampler('feedbackSampler'); points.addTexture2d('feedbackTexture', true); From c86047f020410fc23406acfac412a9581802e9e9 Mon Sep 17 00:00:00 2001 From: Sebastian Sanabria Date: Tue, 27 Jun 2023 18:55:47 -0600 Subject: [PATCH 5/9] Removed assumed 4 byte alignment - Depending on the data type, not all fields in a struct are 4 bytes, a vec2 has 16 bytes because all vectors occupy 16 no matter what, so because of this, now the user has to be conscious about explicitly say the size of the struct. --- src/absulit.points.module.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/absulit.points.module.js b/src/absulit.points.module.js index 1db32a55..a75c6bba 100644 --- a/src/absulit.points.module.js +++ b/src/absulit.points.module.js @@ -949,7 +949,7 @@ export default class Points { if (storageItem.read) { usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC; } - storageItem.buffer = this._createBuffer(storageItem.size * storageItem.structSize * 4, usage); + storageItem.buffer = this._createBuffer(storageItem.size * storageItem.structSize, usage); } }); //-------------------------------------------- @@ -964,7 +964,7 @@ export default class Points { //let layerValues = []; let layersSize = 0; this._layers.forEach(layerItem => { - layersSize += layerItem.size * layerItem.structSize * 4; + layersSize += layerItem.size * layerItem.structSize; }); this._layers.buffer = this._createBuffer(layersSize, GPUBufferUsage.STORAGE); } From ee73201f2cdcd53c3cb2b86ed0fafa89c26e1da8 Mon Sep 17 00:00:00 2001 From: Sebastian Sanabria Date: Tue, 27 Jun 2023 19:09:17 -0600 Subject: [PATCH 6/9] restored layer byte size - This is static, unless I later decide to make it with a dynamic struct, it must remain the same --- src/absulit.points.module.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/absulit.points.module.js b/src/absulit.points.module.js index a75c6bba..d7eb0c62 100644 --- a/src/absulit.points.module.js +++ b/src/absulit.points.module.js @@ -964,7 +964,7 @@ export default class Points { //let layerValues = []; let layersSize = 0; this._layers.forEach(layerItem => { - layersSize += layerItem.size * layerItem.structSize; + layersSize += layerItem.size * layerItem.structSize * 4; }); this._layers.buffer = this._createBuffer(layersSize, GPUBufferUsage.STORAGE); } From e1d56d94566311c8f4c6814e8d157eaa330b4be1 Mon Sep 17 00:00:00 2001 From: Sebastian Sanabria Date: Wed, 28 Jun 2023 19:19:45 -0600 Subject: [PATCH 7/9] added correct bytes --- examples/dithering3_1/index.js | 2 +- examples/dithering3_2/index.js | 2 +- examples/mouseclickscroll1/index.js | 2 +- examples/noise1/index.js | 4 ++-- examples/shapes1/index.js | 2 +- examples/shapes2/index.js | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/dithering3_1/index.js b/examples/dithering3_1/index.js index de5677be..845f76b8 100644 --- a/examples/dithering3_1/index.js +++ b/examples/dithering3_1/index.js @@ -16,7 +16,7 @@ const dithering3 = { await points.addTextureImage('image', './../img/absulit_800x800.jpg'); points.addBindingTexture('outputTex', 'computeTexture'); points.addLayers(2); - points.addStorage('variables', 1, 'Variable', 2, false, ShaderType.COMPUTE); + points.addStorage('variables', 1, 'Variable', 4, false, ShaderType.COMPUTE); }, update: points => { diff --git a/examples/dithering3_2/index.js b/examples/dithering3_2/index.js index a756392e..01fce08a 100644 --- a/examples/dithering3_2/index.js +++ b/examples/dithering3_2/index.js @@ -16,7 +16,7 @@ const dithering3 = { await points.addTextureImage('image', './../img/absulit_800x800.jpg'); points.addBindingTexture('outputTex', 'computeTexture'); points.addLayers(2); - points.addStorage('variables', 1, 'Variable', 2, false, ShaderType.COMPUTE); + points.addStorage('variables', 1, 'Variable', 4, false, ShaderType.COMPUTE); }, update: points => { diff --git a/examples/mouseclickscroll1/index.js b/examples/mouseclickscroll1/index.js index 0b5fa06e..e93107f8 100644 --- a/examples/mouseclickscroll1/index.js +++ b/examples/mouseclickscroll1/index.js @@ -5,7 +5,7 @@ const mouseclickscroll1 = { vert, frag, init: async points => { - points.addStorage('variables', 1, 'Variable', 4); + points.addStorage('variables', 1, 'Variable', 24); }, update: points => { diff --git a/examples/noise1/index.js b/examples/noise1/index.js index 9655fcba..a6adcfda 100644 --- a/examples/noise1/index.js +++ b/examples/noise1/index.js @@ -6,8 +6,8 @@ const noise1 = { init: async points => { const numPoints = 800*800; points.addUniform('value_noise_data_length', numPoints); - points.addStorage('value_noise_data', numPoints, 'f32', 1); - points.addStorage('variables', 1, 'Variable', 1); + points.addStorage('value_noise_data', numPoints, 'f32', 4); + points.addStorage('variables', 1, 'Variable', 4); }, update: points => { diff --git a/examples/shapes1/index.js b/examples/shapes1/index.js index b25f8730..a3954770 100644 --- a/examples/shapes1/index.js +++ b/examples/shapes1/index.js @@ -9,7 +9,7 @@ const shapes1 = { init: async points => { const numPoints = 128; points.addUniform('numPoints', numPoints); - points.addStorage('points', numPoints, 'vec2', 2); + points.addStorage('points', numPoints, 'vec2', 8); }, update: points => { diff --git a/examples/shapes2/index.js b/examples/shapes2/index.js index ea29331b..c4bfd027 100644 --- a/examples/shapes2/index.js +++ b/examples/shapes2/index.js @@ -9,7 +9,7 @@ const shapes2 = { init: async points => { const numPoints = 800*800; points.addUniform('numPoints', numPoints); - points.addStorage('points', numPoints, 'vec4', 4); + points.addStorage('points', numPoints, 'vec4', 16); points.addSampler('feedbackSampler', null); points.addBindingTexture('outputTex', 'computeTexture'); }, From e646a2a4d8d4433a7a47a46c238d0a15db3184d4 Mon Sep 17 00:00:00 2001 From: Sebastian Sanabria Date: Sat, 1 Jul 2023 16:37:14 -0600 Subject: [PATCH 8/9] restored way we calculate storage size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - it was never wrong 😄 - the thing is the error is the parameters sent into addStorage, so I have to be careful there --- src/absulit.points.module.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/absulit.points.module.js b/src/absulit.points.module.js index d7eb0c62..744f04d3 100644 --- a/src/absulit.points.module.js +++ b/src/absulit.points.module.js @@ -274,7 +274,6 @@ export default class Points { this._fitWindow = false; this._lastFitWindow = false; - // _readStorage should only be read once this._readStorageCopied = false; } @@ -747,15 +746,11 @@ export default class Points { let dynamicStructParams = ''; this._uniforms.forEach(variable => { - dynamicStructParams += /*wgsl*/`${variable.name}:f32, \n\t\t\t\t\t`; + dynamicStructParams += /*wgsl*/`${variable.name}:f32, \n\t`; }); if (this._uniforms.length) { - dynamicStructParams = /*wgsl*/` - struct Params { - ${dynamicStructParams} - } - \n`; + dynamicStructParams = /*wgsl*/`struct Params {\n\t${dynamicStructParams}\n}\n`; } renderPass.hasVertexShader && (dynamicGroupBindingsVertex += dynamicStructParams); @@ -949,7 +944,7 @@ export default class Points { if (storageItem.read) { usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC; } - storageItem.buffer = this._createBuffer(storageItem.size * storageItem.structSize, usage); + storageItem.buffer = this._createBuffer(storageItem.size * storageItem.structSize * 4, usage); } }); //-------------------------------------------- @@ -1200,7 +1195,7 @@ export default class Points { } if (this._storage.length) { - this._storage.forEach((storageItem, index) => { + this._storage.forEach(storageItem => { let internalCheck = internal == storageItem.internal; if (!storageItem.shaderType && internalCheck || storageItem.shaderType == shaderType && internalCheck) { entries.push( From 6a082108243149697134c8fcbea2e350e72364f2 Mon Sep 17 00:00:00 2001 From: Sebastian Sanabria Date: Sat, 1 Jul 2023 19:11:33 -0600 Subject: [PATCH 9/9] restored examples storage size - The code is correct and you can count the basic elements of each struct, meaning f32, i32, u32, etc. --- examples/dithering3_1/index.js | 2 +- examples/dithering3_2/index.js | 2 +- examples/mouseclickscroll1/index.js | 2 +- examples/noise1/index.js | 4 ++-- examples/shapes1/index.js | 2 +- examples/shapes2/index.js | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/dithering3_1/index.js b/examples/dithering3_1/index.js index 845f76b8..9486b077 100644 --- a/examples/dithering3_1/index.js +++ b/examples/dithering3_1/index.js @@ -16,7 +16,7 @@ const dithering3 = { await points.addTextureImage('image', './../img/absulit_800x800.jpg'); points.addBindingTexture('outputTex', 'computeTexture'); points.addLayers(2); - points.addStorage('variables', 1, 'Variable', 4, false, ShaderType.COMPUTE); + points.addStorage('variables', 1, 'Variable', 1, false, ShaderType.COMPUTE); }, update: points => { diff --git a/examples/dithering3_2/index.js b/examples/dithering3_2/index.js index 01fce08a..f16e3349 100644 --- a/examples/dithering3_2/index.js +++ b/examples/dithering3_2/index.js @@ -16,7 +16,7 @@ const dithering3 = { await points.addTextureImage('image', './../img/absulit_800x800.jpg'); points.addBindingTexture('outputTex', 'computeTexture'); points.addLayers(2); - points.addStorage('variables', 1, 'Variable', 4, false, ShaderType.COMPUTE); + points.addStorage('variables', 1, 'Variable', 1, false, ShaderType.COMPUTE); }, update: points => { diff --git a/examples/mouseclickscroll1/index.js b/examples/mouseclickscroll1/index.js index e93107f8..0b5fa06e 100644 --- a/examples/mouseclickscroll1/index.js +++ b/examples/mouseclickscroll1/index.js @@ -5,7 +5,7 @@ const mouseclickscroll1 = { vert, frag, init: async points => { - points.addStorage('variables', 1, 'Variable', 24); + points.addStorage('variables', 1, 'Variable', 4); }, update: points => { diff --git a/examples/noise1/index.js b/examples/noise1/index.js index a6adcfda..9655fcba 100644 --- a/examples/noise1/index.js +++ b/examples/noise1/index.js @@ -6,8 +6,8 @@ const noise1 = { init: async points => { const numPoints = 800*800; points.addUniform('value_noise_data_length', numPoints); - points.addStorage('value_noise_data', numPoints, 'f32', 4); - points.addStorage('variables', 1, 'Variable', 4); + points.addStorage('value_noise_data', numPoints, 'f32', 1); + points.addStorage('variables', 1, 'Variable', 1); }, update: points => { diff --git a/examples/shapes1/index.js b/examples/shapes1/index.js index a3954770..b25f8730 100644 --- a/examples/shapes1/index.js +++ b/examples/shapes1/index.js @@ -9,7 +9,7 @@ const shapes1 = { init: async points => { const numPoints = 128; points.addUniform('numPoints', numPoints); - points.addStorage('points', numPoints, 'vec2', 8); + points.addStorage('points', numPoints, 'vec2', 2); }, update: points => { diff --git a/examples/shapes2/index.js b/examples/shapes2/index.js index c4bfd027..ea29331b 100644 --- a/examples/shapes2/index.js +++ b/examples/shapes2/index.js @@ -9,7 +9,7 @@ const shapes2 = { init: async points => { const numPoints = 800*800; points.addUniform('numPoints', numPoints); - points.addStorage('points', numPoints, 'vec4', 16); + points.addStorage('points', numPoints, 'vec4', 4); points.addSampler('feedbackSampler', null); points.addBindingTexture('outputTex', 'computeTexture'); },