diff --git a/engine/playground-render-canvas/src/RenderCanvas.vue b/engine/playground-render-canvas/src/RenderCanvas.vue index d3c452d..c07db29 100644 --- a/engine/playground-render-canvas/src/RenderCanvas.vue +++ b/engine/playground-render-canvas/src/RenderCanvas.vue @@ -2,7 +2,7 @@ import { ComputePipeline } from './compute'; import { GraphicsPipeline, passThroughshaderCode } from './pass_through'; import { NotReadyError, parsePrintfBuffer, sizeFromFormat } from './canvasUtils'; -import type { Bindings, CallCommand, CompiledPlayground, ResourceCommand } from 'slang-playground-shared'; +import { type ResourceCommand, type Bindings, type CallCommand, type CompiledPlayground, type UniformController, type ScalarType, getScalarSize } from 'slang-playground-shared'; import { onMounted, ref, useTemplateRef } from 'vue'; let fileUri: string; @@ -347,55 +347,7 @@ async function execFrame(timeMS: number, playgroundData: CompiledPlayground, fir throw new Error("uniformInput doesn't exist or is of incorrect type"); } - let uniformBufferData = new ArrayBuffer(playgroundData.uniformSize); - let uniformBufferView = new DataView(uniformBufferData); - - for (let uniformComponent of playgroundData.uniformComponents) { - let offset = uniformComponent.buffer_offset; - if (uniformComponent.type == "SLIDER") { - uniformBufferView.setFloat32(offset, uniformComponent.value, true); - } else if (uniformComponent.type == "COLOR_PICK") { - uniformComponent.value.forEach((v, i) => { - uniformBufferView.setFloat32(offset + i * 4, v, true); - }); - } else if (uniformComponent.type == "TIME") { - uniformBufferView.setFloat32(offset, timeMS * 0.001, true); - } else if (uniformComponent.type == "FRAME_ID") { - uniformBufferView.setFloat32(offset, frameID.value, true); - } else if (uniformComponent.type == "MOUSE_POSITION") { - uniformBufferView.setFloat32(offset, canvasCurrentMousePos.x, true); - uniformBufferView.setFloat32(offset + 4, canvasCurrentMousePos.y, true); - uniformBufferView.setFloat32(offset + 8, canvasLastMouseDownPos.x * (canvasIsMouseDown ? -1 : 1), true); - uniformBufferView.setFloat32(offset + 12, canvasLastMouseDownPos.y * (canvasMouseClicked ? -1 : 1), true); - } else if (uniformComponent.type == "KEY") { - // Set 1 or 0 depending on key state, using correct type - const isPressed = pressedKeys.has(uniformComponent.key); - if (uniformComponent.scalarType == "float32") { - uniformBufferView.setFloat32(offset, isPressed ? 1.0 : 0.0, true); - } else if (uniformComponent.scalarType == "float64") { - uniformBufferView.setFloat64(offset, isPressed ? 1.0 : 0.0, true); - } else if (uniformComponent.scalarType == "int8") { - uniformBufferView.setInt8(offset, isPressed ? 1 : 0); - } else if (uniformComponent.scalarType == "int16") { - uniformBufferView.setInt16(offset, isPressed ? 1 : 0, true); - } else if (uniformComponent.scalarType == "int32") { - uniformBufferView.setInt32(offset, isPressed ? 1 : 0, true); - } else if (uniformComponent.scalarType == "uint8") { - uniformBufferView.setUint8(offset, isPressed ? 1 : 0); - } else if (uniformComponent.scalarType == "uint16") { - uniformBufferView.setUint16(offset, isPressed ? 1 : 0, true); - } else if (uniformComponent.scalarType == "uint32") { - uniformBufferView.setUint32(offset, isPressed ? 1 : 0, true); - } else { - throw new Error("KEY_INPUT only scalar type not supported"); - } - } else { - let _: never = uniformComponent; - throw new Error("Invalid state"); - } - } - - device.queue.writeBuffer(uniformInput, 0, new Uint8Array(uniformBufferData)); + writeUniformData(uniformInput, playgroundData.uniformComponents, playgroundData.uniformSize, timeMS); // Encode commands to do the computation const encoder = device.createCommandEncoder({ label: 'compute builtin encoder' }); @@ -574,6 +526,76 @@ async function execFrame(timeMS: number, playgroundData: CompiledPlayground, fir return true; } +function writeScalar(uniformBufferView: DataView, scalarType: ScalarType, offset: number, value: number): boolean { + if (scalarType == "float32") { + uniformBufferView.setFloat32(offset, value, true); + } else if (scalarType == "float64") { + uniformBufferView.setFloat64(offset, value, true); + } else if (scalarType == "int8") { + uniformBufferView.setInt8(offset, value); + } else if (scalarType == "int16") { + uniformBufferView.setInt16(offset, value, true); + } else if (scalarType == "int32") { + uniformBufferView.setInt32(offset, value, true); + } else if (scalarType == "uint8") { + uniformBufferView.setUint8(offset, value); + } else if (scalarType == "uint16") { + uniformBufferView.setUint16(offset, value, true); + } else if (scalarType == "uint32") { + uniformBufferView.setUint32(offset, value, true); + } else { + return false; + } + return true; +} + +function writeUniformData(uniformInput: GPUBuffer, uniformComponents: UniformController[], uniformSize: number, timeMS: number) { + let uniformBufferData = new ArrayBuffer(uniformSize); + let uniformBufferView = new DataView(uniformBufferData); + + for (let uniformComponent of uniformComponents) { + let offset = uniformComponent.buffer_offset; + if (uniformComponent.type == "SLIDER") { + uniformBufferView.setFloat32(offset, uniformComponent.value, true); + } else if (uniformComponent.type == "COLOR_PICK") { + uniformComponent.value.forEach((v, i) => { + uniformBufferView.setFloat32(offset + i * 4, v, true); + }); + } else if (uniformComponent.type == "TIME") { + if(!writeScalar(uniformBufferView, uniformComponent.scalarType, offset, timeMS * 0.001)) { + throw new Error(`scalar type not supported for ${uniformComponent.type} uniform`); + } + } else if (uniformComponent.type == "FRAME_ID") { + if(!writeScalar(uniformBufferView, uniformComponent.scalarType, offset, frameID.value)) { + throw new Error(`scalar type not supported for ${uniformComponent.type} uniform`); + } + } else if (uniformComponent.type == "MOUSE_POSITION") { + let data = [ + canvasCurrentMousePos.x, + canvasCurrentMousePos.y, + canvasLastMouseDownPos.x * (canvasIsMouseDown ? -1 : 1), + canvasLastMouseDownPos.y * (canvasMouseClicked ? -1 : 1), + ]; + for (let i = 0; i < data.length; i++) { + if(!writeScalar(uniformBufferView, uniformComponent.scalarType, offset + i * getScalarSize(uniformComponent.scalarType) / 8, data[i])) { + throw new Error(`scalar type not supported for ${uniformComponent.type} uniform`); + } + } + } else if (uniformComponent.type == "KEY") { + // Set 1 or 0 depending on key state, using correct type + const isPressed = pressedKeys.has(uniformComponent.key); + if(!writeScalar(uniformBufferView, uniformComponent.scalarType, offset, isPressed ? 1 : 0)) { + throw new Error(`scalar type not supported for ${uniformComponent.type} uniform`); + } + } else { + let _: never = uniformComponent; + throw new Error("Invalid state"); + } + } + + device.queue.writeBuffer(uniformInput, 0, new Uint8Array(uniformBufferData)); +} + function safeSet(map: Map, key: string, value: T) { if (map.has(key)) { let currentEntry = map.get(key); @@ -587,7 +609,7 @@ function safeSet(map: Map, key: string, valu async function processResourceCommands( resourceBindings: Bindings, - resourceCommands: ResourceCommand[], + bindingResourceCommands: ResourceCommand[], resourceMetadata: { [k: string]: ResourceMetadata }, uniformSize: number ) { @@ -595,13 +617,14 @@ async function processResourceCommands( safeSet(allocatedResources, "uniformInput", device.createBuffer({ size: uniformSize, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST })); - for (const { resourceName, parsedCommand } of resourceCommands) { + for (const { resourceName, parsedCommand } of bindingResourceCommands) { + const bindingInfo = resourceBindings[resourceName]; + if (!bindingInfo) { + throw new Error(`Resource ${resourceName} is not defined in the bindings.`); + } + if (parsedCommand.type === "ZEROS") { const elementSize = parsedCommand.elementSize; - const bindingInfo = resourceBindings[resourceName]; - if (!bindingInfo) { - throw new Error(`Resource ${resourceName} is not defined in the bindings.`); - } if (!bindingInfo.buffer) { throw new Error(`Resource ${resourceName} is an invalid type for ZEROS`); @@ -638,11 +661,6 @@ async function processResourceCommands( safeSet(allocatedResources, resourceName, sampler); } else if (parsedCommand.type === "BLACK") { const size = parsedCommand.width * parsedCommand.height; - const bindingInfo = resourceBindings[resourceName]; - if (!bindingInfo) { - throw new Error(`Resource ${resourceName} is not defined in the bindings.`); - } - const format = bindingInfo.storageTexture?.format; if (format == undefined) { throw new Error(`Could not find format of ${resourceName}`); @@ -677,12 +695,6 @@ async function processResourceCommands( const height = parsedCommand.height_scale * currentWindowSize[1]; const size = width * height; - const bindingInfo = resourceBindings[resourceName]; - if (!bindingInfo) { - throw new Error(`Resource ${resourceName} is not defined in the bindings.`); - } - - const format = bindingInfo.storageTexture?.format; if (format == undefined) { throw new Error(`Could not find format of ${resourceName}`) @@ -715,17 +727,10 @@ async function processResourceCommands( } } else if (parsedCommand.type === "URL") { // Load image from URL and wait for it to be ready. - const bindingInfo = resourceBindings[resourceName]; - - if (!bindingInfo) { - throw new Error(`Resource ${resourceName} is not defined in the bindings.`); - } - if (!bindingInfo.texture) { throw new Error(`Resource ${resourceName} is not a texture.`); } - const format = parsedCommand.format; const image = new Image(); @@ -759,11 +764,6 @@ async function processResourceCommands( throw new Error(`Failed to create texture from image: ${error}`); } } else if (parsedCommand.type === "DATA") { - const bindingInfo = resourceBindings[resourceName]; - if (!bindingInfo) { - throw new Error(`Resource ${resourceName} is not defined in the bindings.`); - } - if (!bindingInfo.buffer) { throw new Error(`Resource ${resourceName} is not defined as a buffer.`); } @@ -805,10 +805,6 @@ async function processResourceCommands( } } else if (parsedCommand.type === "RAND") { const elementSize = 4; // RAND is only valid for floats - const bindingInfo = resourceBindings[resourceName]; - if (!bindingInfo) { - throw new Error(`Resource ${resourceName} is not defined in the bindings.`); - } if (!bindingInfo.buffer) { throw new Error(`Resource ${resourceName} is not defined as a buffer.`); @@ -830,58 +826,10 @@ async function processResourceCommands( device.queue.writeBuffer(buffer, 0, data); safeSet(allocatedResources, resourceName, buffer); - } else if (parsedCommand.type == "SLIDER") { - const elementSize = parsedCommand.elementSize; - - const buffer = allocatedResources.get("uniformInput") as GPUBuffer - - // Initialize the buffer with the default. - let bufferDefault: BufferSource - if (elementSize == 4) { - bufferDefault = new Float32Array([parsedCommand.default]); - } else - throw new Error("Unsupported float size for slider") - device.queue.writeBuffer(buffer, parsedCommand.offset, bufferDefault); - } else if (parsedCommand.type == "COLOR_PICK") { - const elementSize = parsedCommand.elementSize; - - const buffer = allocatedResources.get("uniformInput") as GPUBuffer - - // Initialize the buffer with the default. - let bufferDefault: BufferSource - if (elementSize == 4) { - bufferDefault = new Float32Array(parsedCommand.default); - } else - throw new Error("Unsupported float size for color pick") - device.queue.writeBuffer(buffer, parsedCommand.offset, bufferDefault); - } else if (parsedCommand.type == "TIME") { - const buffer = allocatedResources.get("uniformInput") as GPUBuffer - - // Initialize the buffer with zeros. - let bufferDefault: BufferSource = new Float32Array([0.0]); - device.queue.writeBuffer(buffer, parsedCommand.offset, bufferDefault); - } else if (parsedCommand.type == "FRAME_ID") { - const buffer = allocatedResources.get("uniformInput") as GPUBuffer - - // Initialize the buffer with zeros. - let bufferDefault: BufferSource = new Float32Array([0.0]); - device.queue.writeBuffer(buffer, parsedCommand.offset, bufferDefault); - } else if (parsedCommand.type == "MOUSE_POSITION") { - const buffer = allocatedResources.get("uniformInput") as GPUBuffer - - // Initialize the buffer with zeros. - let bufferDefault: BufferSource = new Float32Array([0, 0, 0, 0]); - device.queue.writeBuffer(buffer, parsedCommand.offset, bufferDefault); - } else if (parsedCommand.type == "KEY") { - const buffer = allocatedResources.get("uniformInput") as GPUBuffer - - // Initialize the buffer with zeros. - let bufferDefault: BufferSource = new Float32Array([0]); - device.queue.writeBuffer(buffer, parsedCommand.offset, bufferDefault); } else { // exhaustiveness check let x: never = parsedCommand; - throw new Error("Invalid resource command type"); + throw new Error("Invalid binding command type"); } } @@ -987,6 +935,13 @@ function onRun(runCompiledCode: CompiledPlayground) { compiledCode.uniformSize ); + writeUniformData( + allocatedResources.get("uniformInput") as GPUBuffer, + compiledCode.uniformComponents, + compiledCode.uniformSize, + 0.0, + ) + if (!passThroughPipeline) { passThroughPipeline = new GraphicsPipeline(device); const shaderModule = device.createShaderModule({ code: passThroughshaderCode }); diff --git a/engine/shared/src/index.ts b/engine/shared/src/index.ts index c249797..32bbdf9 100644 --- a/engine/shared/src/index.ts +++ b/engine/shared/src/index.ts @@ -1,7 +1,12 @@ -import { UniformController } from './playgroundInterface'; +import { ScalarType, UniformController } from './playgroundInterface'; export * from './playgroundInterface'; export function isControllerRendered(controller: UniformController) { return controller.type == "SLIDER" || controller.type == "COLOR_PICK"; +} + +export function getScalarSize(scalarType: ScalarType): 8 | 16 | 32 | 64 { + let size = parseInt(scalarType.replace(/^[a-z]*/, "")); + return size as any; } \ No newline at end of file diff --git a/engine/shared/src/playgroundInterface.ts b/engine/shared/src/playgroundInterface.ts index 77102cd..df965b5 100644 --- a/engine/shared/src/playgroundInterface.ts +++ b/engine/shared/src/playgroundInterface.ts @@ -113,10 +113,13 @@ export type UniformController = { buffer_offset: number } & ({ value: [number, number, number], } | { type: "TIME", + scalarType: ScalarType, } | { type: "FRAME_ID", + scalarType: ScalarType, } | { type: "MOUSE_POSITION", + scalarType: ScalarType, } | { type: "KEY", key: string, @@ -166,32 +169,6 @@ export type ParsedCommand = { "type": "DATA", "url": string, "elementSize": number, -} | { - "type": "SLIDER", - "default": number, - "min": number, - "max": number, - "elementSize": number, - "offset": number, -} | { - "type": "COLOR_PICK", - "default": [number, number, number], - "elementSize": number, - "offset": number, -} | { - "type": "TIME", - "offset": number, -} | { - "type": "FRAME_ID", - "offset": number, -} | { - "type": "MOUSE_POSITION", - "offset": number, -} | { - "type": "KEY", - key: string, - offset: number, - scalarType: ScalarType, } | { "type": "SAMPLER" }; diff --git a/engine/slang-compilation-engine/media/playgroundDocumentation.md b/engine/slang-compilation-engine/media/playgroundDocumentation.md index 2fcf53d..29fad15 100644 --- a/engine/slang-compilation-engine/media/playgroundDocumentation.md +++ b/engine/slang-compilation-engine/media/playgroundDocumentation.md @@ -75,15 +75,15 @@ Initialize a `float` buffer with uniform random floats between 0 and 1. ### `[playground::TIME]` -Gives a `float` uniform the current time in milliseconds. +Gives a scalar uniform the current time in milliseconds. ### `[playground::FRAME_ID]` -Gives a `float` uniform the current frame index (starting from 0). +Gives a scalar uniform the current frame index (starting from 0). ### `[playground::MOUSE_POSITION]` -Gives a `float4` uniform mouse data. +Gives a 4 component vector uniform mouse data. * `xy`: mouse position (in pixels) during last button down * `abs(zw)`: mouse position during last button click diff --git a/engine/slang-compilation-engine/src/compilationUtils.ts b/engine/slang-compilation-engine/src/compilationUtils.ts index 7ea739c..31f3e56 100644 --- a/engine/slang-compilation-engine/src/compilationUtils.ts +++ b/engine/slang-compilation-engine/src/compilationUtils.ts @@ -1,4 +1,4 @@ -import { ScalarType, SlangFormat } from "slang-playground-shared"; +import { getScalarSize, ScalarType, SlangFormat } from "slang-playground-shared"; export const ACCESS_MAP = { "readWrite": "read-write", @@ -82,9 +82,4 @@ function getWebGPURepresentation(scalarType: ScalarType): ScalarRepresentation { type = "sint"; return `${size}${type}` as any -} - -function getScalarSize(scalarType: ScalarType): 8 | 16 | 32 | 64 { - let size = parseInt(scalarType.replace(/^[a-z]*/, "")); - return size as any; } \ No newline at end of file diff --git a/engine/slang-compilation-engine/src/playgroundCompiler.ts b/engine/slang-compilation-engine/src/playgroundCompiler.ts index dcee2e7..ff3deb5 100644 --- a/engine/slang-compilation-engine/src/playgroundCompiler.ts +++ b/engine/slang-compilation-engine/src/playgroundCompiler.ts @@ -1,4 +1,4 @@ -import { Bindings, CallCommand, CompiledPlayground, OutputType, ParsedCommand, ReflectionJSON, ReflectionParameter, ReflectionType, ResourceCommand, Result, ScalarType, Shader, UniformController } from "slang-playground-shared"; +import { ParsedCommand, ResourceCommand, Bindings, CallCommand, CompiledPlayground, OutputType, ReflectionJSON, ReflectionParameter, ReflectionType, ReflectionUserAttribute, Result, ScalarType, Shader, UniformController } from "slang-playground-shared"; import { ACCESS_MAP, webgpuFormatfromSlangFormat, getTextureFormat } from "./compilationUtils"; export function compilePlayground(compilation: Shader, uri: string): Result { @@ -21,12 +21,16 @@ export function compilePlayground(compilation: Shader, uri: string): Result { +function getParsedCommandsFromAttributes(reflection: ReflectionJSON): Result { let commands: { resourceName: string, parsedCommand: ParsedCommand }[] = []; for (let parameter of reflection.parameters) { @@ -258,14 +262,14 @@ function getResourceCommandsFromAttributes(reflection: ReflectionJSON): Result> = + T & { [s: string]: T[keyof T] | undefined }; +const UNIFORM_PARSERS: WithStringIndex<{ [k in UniformController["type"]]: (parameter: ReflectionParameter & { binding: { kind: "uniform" } }, attribute: ReflectionUserAttribute) => Result> }> = { + SLIDER: function (parameter, attribute) { + if (parameter.type.kind != "scalar" || !parameter.type.scalarType.startsWith("float") || parameter.binding.size != 4) { + return { + succ: false, + message: `SLIDER attribute cannot be applied to ${parameter.name}, it only supports 32 bit floats`, + }; + } + + return { + succ: true, + result: { + name: parameter.name, + value: attribute.arguments[0] as number, + min: attribute.arguments[1] as number, + max: attribute.arguments[2] as number, + } + }; + }, + COLOR_PICK: function (parameter, attribute) { + if (parameter.type.kind != "vector" || parameter.type.elementCount <= 2 || parameter.type.elementType.kind != "scalar" || !parameter.type.elementType.scalarType.startsWith("float") || parseInt(parameter.type.elementType.scalarType.slice(5)) / 8 != 4) { + return { + succ: false, + message: `COLOR_PICK attribute cannot be applied to ${parameter.name}, it only supports 32 bit float vectors`, + }; + } + + return { + succ: true, + result: { + name: parameter.name, + value: attribute.arguments as [number, number, number], + elementSize: parseInt(parameter.type.elementType.scalarType.slice(5)) / 8, + } + }; + }, + TIME: function (parameter) { + if (parameter.type.kind != "scalar") { + return { + succ: false, + message: `TIME attribute cannot be applied to ${parameter.name}, it only supports scalars`, + }; + } + return { + succ: true, + result: { + scalarType: parameter.type.scalarType, + } + }; + }, + FRAME_ID: function (parameter) { + if (parameter.type.kind != "scalar") { + return { + succ: false, + message: `FRAME_ID attribute cannot be applied to ${parameter.name}, it only supports scalars`, + }; + } + return { + succ: true, + result: { + scalarType: parameter.type.scalarType, + } + }; + }, + MOUSE_POSITION: function (parameter) { + if (parameter.type.kind != "vector" || parameter.type.elementCount <= 3 || parameter.type.elementType.kind != "scalar") { + return { + succ: false, + message: `MOUSE_POSITION attribute cannot be applied to ${parameter.name}, it only supports vectors`, + }; + } + return { + succ: true, + result: { + scalarType: parameter.type.elementType.scalarType, + } + }; + }, + KEY: function (parameter, attribute) { + // Only allow on scalar uniforms (float or int) + if (parameter.type.kind != "scalar") { + return { + succ: false, + message: `KEY attribute on ${parameter.name} can only be applied to scalar uniforms`, + }; + } + if (!attribute.arguments || attribute.arguments.length !== 1 || typeof attribute.arguments[0] !== "string") { + return { + succ: false, + message: `KEY attribute on ${parameter.name} requires a single string argument (the key name)`, + }; + } + return { + succ: true, + result: { + key: attribute.arguments[0] as string, + scalarType: parameter.type.scalarType, + } + }; + } +} + +function getUniformControllersFromAttributes(reflection: ReflectionJSON): Result { + let commands: UniformController[] = []; + + for (let parameter of reflection.parameters) { + if (parameter.userAttribs == undefined) continue; + for (let attribute of parameter.userAttribs) { + if (!attribute.name.startsWith("playground_")) continue; + + let playground_attribute_name = attribute.name.slice(11); + let parser = UNIFORM_PARSERS[playground_attribute_name]; + if (parser == undefined) { + continue; + } + + if (parameter.binding.kind != "uniform") { + return { + succ: false, + message: `${playground_attribute_name} attribute must be applied to uniform`, + }; + } + + let parsedUniformControllerResult = parser(parameter as ReflectionParameter & { binding: { kind: "uniform" } }, attribute) + if (parsedUniformControllerResult.succ == false) { + return parsedUniformControllerResult; + } + + let parsedController = { + type: playground_attribute_name, + buffer_offset: parameter.binding.offset, + ...parsedUniformControllerResult.result + } as UniformController; + + commands.push(parsedController); + } + } + + return { + succ: true, + result: commands, + }; +} + function getUniformSize(reflection: ReflectionJSON): number { let size = 0; @@ -401,52 +470,6 @@ function roundUpToNearest(x: number, nearest: number) { return Math.ceil(x / nearest) * nearest; } -function getUniformControllers(resourceCommands: ResourceCommand[]): UniformController[] { - let controllers: UniformController[] = []; - for (let resourceCommand of resourceCommands) { - if (resourceCommand.parsedCommand.type == 'SLIDER') { - controllers.push({ - type: resourceCommand.parsedCommand.type, - buffer_offset: resourceCommand.parsedCommand.offset, - name: resourceCommand.resourceName, - value: resourceCommand.parsedCommand.default, - min: resourceCommand.parsedCommand.min, - max: resourceCommand.parsedCommand.max, - }) - } else if (resourceCommand.parsedCommand.type == 'COLOR_PICK') { - controllers.push({ - type: resourceCommand.parsedCommand.type, - buffer_offset: resourceCommand.parsedCommand.offset, - name: resourceCommand.resourceName, - value: resourceCommand.parsedCommand.default, - }) - } else if (resourceCommand.parsedCommand.type == 'TIME') { - controllers.push({ - type: resourceCommand.parsedCommand.type, - buffer_offset: resourceCommand.parsedCommand.offset, - }) - } else if (resourceCommand.parsedCommand.type == 'FRAME_ID') { - controllers.push({ - type: resourceCommand.parsedCommand.type, - buffer_offset: resourceCommand.parsedCommand.offset, - }) - } else if (resourceCommand.parsedCommand.type == 'MOUSE_POSITION') { - controllers.push({ - type: resourceCommand.parsedCommand.type, - buffer_offset: resourceCommand.parsedCommand.offset, - }) - } else if (resourceCommand.parsedCommand.type == 'KEY') { - controllers.push({ - type: resourceCommand.parsedCommand.type, - buffer_offset: resourceCommand.parsedCommand.offset, - key: resourceCommand.parsedCommand.key, - scalarType: resourceCommand.parsedCommand.scalarType, - }) - } - } - return controllers; -} - function parseCallCommands(reflection: ReflectionJSON): Result { const callCommands: CallCommand[] = []; diff --git a/public/demos/painting.slang b/public/demos/painting.slang index de0c43b..a23e03a 100644 --- a/public/demos/painting.slang +++ b/public/demos/painting.slang @@ -16,7 +16,7 @@ uniform float brush_size; uniform float3 color; [playground::MOUSE_POSITION] -uniform float4 mousePosition; +uniform int4 mousePosition; [shader("compute")] [numthreads(1, 1, 1)] @@ -31,19 +31,19 @@ void update(uint2 dispatchThreadId: SV_DispatchThreadID) [shader("compute")] [numthreads(THREAD_COUNT, THREAD_COUNT, 1)] [playground::CALL_INDIRECT("indirectBuffer", 0)] -void draw(uint2 dispatchThreadId: SV_DispatchThreadID) +void draw(int2 dispatchThreadId: SV_DispatchThreadID) { if (mousePosition.z >= 0) return; - let offset = float2(dispatchThreadId.xy) - brush_size; + let offset = dispatchThreadId.xy - int2(brush_size); if (length(offset) > brush_size / 2) return; uint2 screenSize; tex.GetDimensions(screenSize.x, screenSize.y); - var mouse_pos = int2(0, screenSize.y) + int2(1, -1) * int2(mousePosition.xy + offset); + var mouse_pos = int2(0, screenSize.y) + int2(1, -1) * mousePosition.xy + offset; drawPixel(mouse_pos, (int2 screenSize) => { return float4(color, 1.0); }); diff --git a/src/components/Help.vue b/src/components/Help.vue index 0f6a2c9..428a8c4 100644 --- a/src/components/Help.vue +++ b/src/components/Help.vue @@ -66,11 +66,11 @@ defineExpose({

[playground::RAND(1000)]

Initialize a float buffer with uniform random floats between 0 and 1.

[playground::TIME]

- Gives a float uniform the current time in milliseconds. + Gives a scalar uniform the current time in milliseconds.

[playground::FRAME_ID]

- Gives a float uniform the current frame index (starting from 0). + Gives a scalar uniform the current frame index (starting from 0).

[playground::MOUSE_POSITION]

- Gives a float4 uniform mouse data. + Gives a 4 component vector uniform mouse data.
  • xy: mouse position (in pixels) during last button down.
  • abs(zw): mouse position during last button click.