Rework garden simulation pipelines

This commit is contained in:
Andras Schmelczer 2026-05-24 10:58:11 +01:00
commit 018f8c9d4d
67 changed files with 6499 additions and 1682 deletions

View file

@ -1,63 +1,124 @@
import { vec2 } from 'gl-matrix';
import { CopyPipeline } from '../../pipelines/copy/copy-pipeline';
import { TRAIL_SOURCE_TEXTURE_FORMAT } from '../../pipelines/texture-formats';
interface ResizableTextureOptions {
clearValue?: GPUColor;
format?: GPUTextureFormat;
usage?: GPUTextureUsageFlags;
}
export interface PendingTextureResize {
copySize: GPUExtent3DStrict;
newSize: vec2;
newTexture: GPUTexture;
newTextureView: GPUTextureView;
oldTexture: GPUTexture;
}
export class ResizableTexture {
private texture: GPUTexture;
private textureView: GPUTextureView;
private size: vec2;
private readonly copyPipeline: CopyPipeline;
private readonly clearValue: GPUColor;
private readonly format: GPUTextureFormat;
private readonly usage: GPUTextureUsageFlags;
public constructor(
private readonly device: GPUDevice,
size: vec2
size: vec2,
{
clearValue = { r: 0, g: 0, b: 0, a: 0 },
format = TRAIL_SOURCE_TEXTURE_FORMAT,
usage = defaultTextureUsage,
}: ResizableTextureOptions = {}
) {
this.copyPipeline = new CopyPipeline(this.device);
this.size = size;
this.size = vec2.clone(size);
this.clearValue = clearValue;
this.format = format;
this.usage = usage;
this.texture = this.createTexture(size);
this.textureView = this.texture.createView();
}
public resize(size: vec2): void {
public prepareResize(size: vec2): PendingTextureResize | null {
if (vec2.equals(this.size, size)) {
return;
return null;
}
const newTexture = this.createTexture(size);
const newTextureView = newTexture.createView();
const copySize = {
width: Math.min(this.size[0], size[0]),
height: Math.min(this.size[1], size[1]),
};
const commandEncoder = this.device.createCommandEncoder();
this.copyPipeline.execute(
commandEncoder,
this.textureView,
return {
copySize,
newSize: vec2.clone(size),
newTexture,
newTextureView,
vec2.div(vec2.create(), this.size, size)
);
this.device.queue.submit([commandEncoder.finish()]);
this.texture.destroy();
oldTexture: this.texture,
};
}
this.size = size;
this.texture = newTexture;
this.textureView = newTextureView;
public encodeResize(
commandEncoder: GPUCommandEncoder,
resize: PendingTextureResize
): void {
const clearPass = commandEncoder.beginRenderPass({
colorAttachments: [
{
view: resize.newTextureView,
clearValue: this.clearValue,
loadOp: 'clear',
storeOp: 'store',
},
],
});
clearPass.end();
commandEncoder.copyTextureToTexture(
{ texture: resize.oldTexture },
{ texture: resize.newTexture },
resize.copySize
);
}
public commitResize(resize: PendingTextureResize): void {
resize.oldTexture.destroy();
this.size = resize.newSize;
this.texture = resize.newTexture;
this.textureView = resize.newTextureView;
}
public getSize(): vec2 {
return vec2.clone(this.size);
}
public getTextureView(): GPUTextureView {
return this.textureView;
}
public getTexture(): GPUTexture {
return this.texture;
}
public destroy(): void {
this.texture.destroy();
this.copyPipeline.destroy();
}
private createTexture(size: vec2): GPUTexture {
return this.device.createTexture({
format: 'rgba16float',
format: this.format,
size: { width: size[0], height: size[1] },
usage:
GPUTextureUsage.STORAGE_BINDING |
GPUTextureUsage.TEXTURE_BINDING |
GPUTextureUsage.RENDER_ATTACHMENT,
usage: this.usage,
});
}
}
const defaultTextureUsage =
GPUTextureUsage.STORAGE_BINDING |
GPUTextureUsage.TEXTURE_BINDING |
GPUTextureUsage.RENDER_ATTACHMENT |
GPUTextureUsage.COPY_SRC |
GPUTextureUsage.COPY_DST;