Running kernels
Forms that compile (8)
Section titled “Forms that compile (8)”| Syntax | Description |
|---|---|
Gpu.Buffer(64, 64) | Creating a buffer |
Gpu.Swap(ref a, ref b) | Swapping the two |
Gpu.Run(nameof(Step), next, current) | Calling Run |
Gpu.Run(nameof(Step), next, current, phase) | Running with extra arguments |
Gpu.Run("Step", next, current) | Naming a kernel with a string |
Gpu.Run(nameof(Fade), current, next) | Multiple kernels |
Gpu.Show(current, display) | Displaying it on a surface |
Gpu.Texture(current) | Retrieving it as a texture |
Forms that don’t compile (8)
Section titled “Forms that don’t compile (8)”| Syntax | Description | Error | Reason | Instead |
|---|---|---|---|---|
The kernel isn’t static | A method with [TsukimiKernel] that’s an instance method | TUKI0001 | by design | Make it static |
The return type isn’t Color4 | The kernel returns a different type | TUKI0001 | by design | Return Color4 |
The first argument isn’t KernelId | The kernel’s argument order is wrong | TUKI0001 | by design | Make the first argument KernelId |
The argument count for Gpu.Run doesn’t match | The count differs from the kernel’s arguments | TUKI0001 | by design | Match the count |
The argument types for Gpu.Run don’t match | The types differ from the kernel’s arguments | TUKI0001 | by design | Match the types |
Gpu.Run(k, next, next) | The output buffer is also passed as an input | TUKI0001 | by design | Pass a different buffer |
Gpu.Run("NotAKernel", ...) | Passing the name of a method without [TsukimiKernel] | TUKI0001 | by design | Fix the spelling with nameof |
Calling Gpu.Pack16x2 outside a kernel | The packing is written outside the kernel | TUKI0001, TUKI0099, TUKI0102 | by design | Pack it inside the kernel |
Errors that don’t state the cause
Section titled “Errors that don’t state the cause”All 8 forms above are rejected with the same message (TUKI0001, “This C# syntax can’t be lowered to Udon.”
For the last one only, it also states that there’s no type). Each one breaks a kernel rule, but
the message talks about Udon, so you can’t narrow down the cause from the wording. When you’re rejected, the fastest
path is to check the rows of the table above, from the top.
Forgetting to assign the surface
Section titled “Forgetting to assign the surface”Writing one kernel adds one public field for wiring the display surface. If you leave it unassigned
and get as far as Gpu.Show, it silently stops on the actual hardware. The compiler only issues a warning for this;
compilation still succeeds.
Buffers
Section titled “Buffers”Creating a buffer
Section titled “Creating a buffer”Each cell has 4 components at 8 bits each, and the contents start at zero.
using UnityEngine;using Tsukimi;
public class ParHostBuffer : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(prev[id].R, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); }}Swapping the two
Section titled “Swapping the two”Use this when feeding the previous result back in as the next input. You can’t use ref on the arguments of a method you write yourself, but you can use it with Gpu.Swap.
using UnityEngine;using Tsukimi;
public class ParHostSwap : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(prev[id].R, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}Running
Section titled “Running”Calling Run
Section titled “Calling Run”The second argument is the output. The third argument onward corresponds, in order, to the kernel’s second argument onward.
using UnityEngine;using Tsukimi;
public class ParHostRun : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(prev[id].R, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}Running with extra arguments
Section titled “Running with extra arguments”The count and types of the values you pass are checked against the kernel’s arguments at compile time.
using UnityEngine;using Tsukimi;
public class ParHostRunExtraArgs : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next; private float phase;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev, float t) { return new Color4(prev[id].R * t, 0f, 0f, 1f); }
void Update() { phase = phase + Time.deltaTime; Gpu.Run(nameof(Step), next, current, phase); }}Naming a kernel with a string
Section titled “Naming a kernel with a string”The kernel’s name can also be passed as a string. Using nameof lets C# catch a misspelling.
using UnityEngine;using Tsukimi;
public class ParHostRunStringName : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(prev[id].R, 0f, 0f, 1f); }
void Update() { Gpu.Run("Step", next, current); }}Multiple kernels
Section titled “Multiple kernels”You can write multiple kernels and run them in sequence.
using UnityEngine;using Tsukimi;
public class ParHostTwoKernels : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(prev[id].R, 0f, 0f, 1f); }
[TsukimiKernel] static Color4 Fade(KernelId id, GpuBuffer2D prev) { return new Color4(prev[id].R * 0.5f, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Run(nameof(Fade), current, next); }}Display and retrieval
Section titled “Display and retrieval”Displaying it on a surface
Section titled “Displaying it on a surface”Calling Gpu.Show replaces the target material’s main texture with the buffer (the material becomes a per-target copy).
using UnityEngine;using Tsukimi;
public class ParHostShow : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next; public Renderer display;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(prev[id].R, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); Gpu.Show(current, display); }}Retrieving it as a texture
Section titled “Retrieving it as a texture”Gpu.Texture is used when passing to a Unity or VRChat-side API. What’s returned is the buffer itself, not a copy.
using UnityEngine;using Tsukimi;
public class ParHostTexture : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next; private RenderTexture tex;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(prev[id].R, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); tex = Gpu.Texture(current); }}