simplify more

This commit is contained in:
Andras Schmelczer 2026-05-20 21:37:30 +01:00
commit 2fe3c69963
40 changed files with 690 additions and 873 deletions

View file

@ -1,25 +1,9 @@
const AGENT_WORKGROUP_SIZE = 64;
const AGENT_MAX_DISPATCH_WORKGROUPS_PER_DIMENSION = 65_535;
export const AGENT_MAX_DISPATCHABLE_COUNT =
AGENT_MAX_DISPATCH_WORKGROUPS_PER_DIMENSION * AGENT_WORKGROUP_SIZE;
const getAgentDispatchWorkgroups = (agentCount: number): [number, number] => {
if (!Number.isFinite(agentCount) || agentCount <= 0) {
throw new Error('Agent count must be a positive finite number');
}
const workgroupCount = Math.ceil(agentCount / AGENT_WORKGROUP_SIZE);
if (workgroupCount > AGENT_MAX_DISPATCH_WORKGROUPS_PER_DIMENSION) {
throw new Error('Agent count exceeds dispatchable workgroup range');
}
return [workgroupCount, 1];
};
export const AGENT_MAX_DISPATCHABLE_COUNT = 65_535 * AGENT_WORKGROUP_SIZE;
export const dispatchAgentWorkgroups = (
passEncoder: GPUComputePassEncoder,
agentCount: number
): void => {
const [workgroupX, workgroupY] = getAgentDispatchWorkgroups(agentCount);
passEncoder.dispatchWorkgroups(workgroupX, workgroupY);
passEncoder.dispatchWorkgroups(Math.ceil(agentCount / AGENT_WORKGROUP_SIZE), 1);
};

View file

@ -1,5 +1,6 @@
import { vec2 } from 'gl-matrix';
import { createBindGroupCache } from '../../../utils/graphics/bind-group-cache';
import { smartCompile } from '../../../utils/graphics/smart-compile';
import { AGENT_MAX_DISPATCHABLE_COUNT, dispatchAgentWorkgroups } from '../agent-dispatch';
import compactionShader from './agent-compaction.wgsl?raw';
@ -17,10 +18,18 @@ export class AgentGenerationPipeline {
private readonly bindGroupLayout: GPUBindGroupLayout;
private readonly uniforms: GPUBuffer;
private readonly bindGroupsByActiveBuffer = new WeakMap<
GPUBuffer,
WeakMap<GPUBuffer, GPUBindGroup>
>();
private readonly bindGroupCache = createBindGroupCache<GPUBuffer, GPUBuffer>(
(active, inactive) =>
this.device.createBindGroup({
layout: this.bindGroupLayout,
entries: [
{ binding: 0, resource: { buffer: this.uniforms } },
{ binding: 1, resource: { buffer: active } },
{ binding: 2, resource: { buffer: this.countersBuffer } },
{ binding: 3, resource: { buffer: inactive } },
],
})
);
private readonly resizePipeline: GPUComputePipeline;
private readonly compactionPipeline: GPUComputePipeline;
@ -244,7 +253,6 @@ export class AgentGenerationPipeline {
this.resizeUniformFloatValues[0] = scale[0];
this.resizeUniformFloatValues[1] = scale[1];
this.resizeUniformUintValues[2] = Math.max(0, Math.floor(agentCount));
this.resizeUniformUintValues[3] = 0;
this.device.queue.writeBuffer(this.uniforms, 0, this.resizeUniformBuffer);
const commandEncoder = this.device.createCommandEncoder();
@ -314,49 +322,7 @@ export class AgentGenerationPipeline {
}
private getBindGroup(): GPUBindGroup {
let inactiveCache = this.bindGroupsByActiveBuffer.get(this.activeAgentsBuffer);
if (!inactiveCache) {
inactiveCache = new WeakMap<GPUBuffer, GPUBindGroup>();
this.bindGroupsByActiveBuffer.set(this.activeAgentsBuffer, inactiveCache);
}
const cached = inactiveCache.get(this.inactiveAgentsBuffer);
if (cached) {
return cached;
}
const bindGroup = this.device.createBindGroup({
layout: this.bindGroupLayout,
entries: [
{
binding: 0,
resource: {
buffer: this.uniforms,
},
},
{
binding: 1,
resource: {
buffer: this.activeAgentsBuffer,
},
},
{
binding: 2,
resource: {
buffer: this.countersBuffer,
},
},
{
binding: 3,
resource: {
buffer: this.inactiveAgentsBuffer,
},
},
],
});
inactiveCache.set(this.inactiveAgentsBuffer, bindGroup);
return bindGroup;
return this.bindGroupCache(this.activeAgentsBuffer, this.inactiveAgentsBuffer);
}
private swapAgentBuffers(): void {

View file

@ -1,7 +1,6 @@
struct ResizeSettings {
scale: vec2<f32>,
agentCount: u32,
padding: u32,
};
@group(1) @binding(0) var<uniform> resizeSettings: ResizeSettings;

View file

@ -6,9 +6,38 @@ import { smartCompile } from '../../utils/graphics/smart-compile';
import { CommonState } from '../common-state/common-state';
import { dispatchAgentWorkgroups } from './agent-dispatch';
import agentSchema from './agent-generation/agent-schema.wgsl?raw';
import { AgentSettings } from './agent-settings';
import shader from './agent.wgsl?raw';
export interface AgentSettings {
color1ToColor1: number;
color1ToColor2: number;
color1ToColor3: number;
color2ToColor1: number;
color2ToColor2: number;
color2ToColor3: number;
color3ToColor1: number;
color3ToColor2: number;
color3ToColor3: number;
moveSpeed: number;
turnSpeed: number;
sensorOffsetAngle: number;
sensorOffsetDistance: number;
turnWhenLost: number;
individualTrailWeight: number;
forwardRotationScale: number;
introNearDistanceMin: number;
introNearSensorOffsetMultiplier: number;
introTargetAngleBlend: number;
introProgressCutoff: number;
introNearDistanceInner: number;
introTurnRateMultiplier: number;
introRandomTurnMultiplier: number;
introFarMoveMultiplier: number;
introNearMoveMultiplier: number;
introStepStopDistance: number;
randomTimeScale: number;
}
export class AgentPipeline {
private static readonly UNIFORM_COUNT = 30;

View file

@ -1,29 +0,0 @@
export interface AgentSettings {
color1ToColor1: number;
color1ToColor2: number;
color1ToColor3: number;
color2ToColor1: number;
color2ToColor2: number;
color2ToColor3: number;
color3ToColor1: number;
color3ToColor2: number;
color3ToColor3: number;
moveSpeed: number;
turnSpeed: number;
sensorOffsetAngle: number;
sensorOffsetDistance: number;
turnWhenLost: number;
individualTrailWeight: number;
forwardRotationScale: number;
introNearDistanceMin: number;
introNearSensorOffsetMultiplier: number;
introTargetAngleBlend: number;
introProgressCutoff: number;
introNearDistanceInner: number;
introTurnRateMultiplier: number;
introRandomTurnMultiplier: number;
introFarMoveMultiplier: number;
introNearMoveMultiplier: number;
introStepStopDistance: number;
randomTimeScale: number;
}