Add simple tests & remove !

This commit is contained in:
Andras Schmelczer 2026-05-04 10:31:46 +01:00
commit be0a49a11f
17 changed files with 1418 additions and 124 deletions

View file

@ -13,75 +13,77 @@ export const generateNoise = ({
height: number;
}): GPUTextureView => {
const cacheKey = `${width}x${height}`;
if (!textureCache.has(cacheKey)) {
const { buffer, vertex } = setUpFullScreenQuad(device);
const vertexBuffer = buffer;
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex,
fragment: {
module: smartCompile(
device,
/* wgsl */ `
fn random_with_seed(uv: vec2<f32>, seed: f32) -> f32 {
return fract(sin(dot(uv, vec2(12.9898 + seed, 78.233 + seed)))* 43758.5453123 + seed);
}
@fragment
fn fragment(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
return vec4(
random_with_seed(uv, 0),
random_with_seed(uv, 1),
random_with_seed(uv, 2),
random_with_seed(uv, 3),
);
}`
),
entryPoint: 'fragment',
targets: [
{
format: 'rgba16float',
},
],
},
primitive: {
topology: 'triangle-strip',
},
});
const colorTexture = device.createTexture({
size: {
width,
height,
depthOrArrayLayers: 1,
},
format: 'rgba16float',
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
});
const renderPassDescriptor: GPURenderPassDescriptor = {
colorAttachments: [
{
view: colorTexture.createView(),
clearValue: { r: 1.0, g: 1.0, b: 1.0, a: 1.0 },
loadOp: 'clear',
storeOp: 'store',
},
],
};
const commandEncoder = device.createCommandEncoder();
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.setPipeline(pipeline);
passEncoder.setVertexBuffer(0, vertexBuffer);
passEncoder.draw(4, 1);
passEncoder.end();
device.queue.submit([commandEncoder.finish()]);
textureCache.set(cacheKey, colorTexture);
const cached = textureCache.get(cacheKey);
if (cached) {
return cached.createView();
}
return textureCache.get(cacheKey)!.createView();
const { buffer, vertex } = setUpFullScreenQuad(device);
const vertexBuffer = buffer;
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex,
fragment: {
module: smartCompile(
device,
/* wgsl */ `
fn random_with_seed(uv: vec2<f32>, seed: f32) -> f32 {
return fract(sin(dot(uv, vec2(12.9898 + seed, 78.233 + seed)))* 43758.5453123 + seed);
}
@fragment
fn fragment(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
return vec4(
random_with_seed(uv, 0),
random_with_seed(uv, 1),
random_with_seed(uv, 2),
random_with_seed(uv, 3),
);
}`
),
entryPoint: 'fragment',
targets: [
{
format: 'rgba16float',
},
],
},
primitive: {
topology: 'triangle-strip',
},
});
const colorTexture = device.createTexture({
size: {
width,
height,
depthOrArrayLayers: 1,
},
format: 'rgba16float',
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
});
const renderPassDescriptor: GPURenderPassDescriptor = {
colorAttachments: [
{
view: colorTexture.createView(),
clearValue: { r: 1.0, g: 1.0, b: 1.0, a: 1.0 },
loadOp: 'clear',
storeOp: 'store',
},
],
};
const commandEncoder = device.createCommandEncoder();
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.setPipeline(pipeline);
passEncoder.setVertexBuffer(0, vertexBuffer);
passEncoder.draw(4, 1);
passEncoder.end();
device.queue.submit([commandEncoder.finish()]);
textureCache.set(cacheKey, colorTexture);
return colorTexture.createView();
};

View file

@ -3,49 +3,38 @@ import { vec2 } from 'gl-matrix';
import { CopyPipeline } from '../../pipelines/copy/copy-pipeline';
export class ResizableTexture {
private texture!: GPUTexture;
private textureView!: GPUTextureView;
private texture: GPUTexture;
private textureView: GPUTextureView;
private size: vec2;
private readonly copyPipeline: CopyPipeline;
private size: vec2 | null = null;
public constructor(
private readonly device: GPUDevice,
size: vec2
) {
this.copyPipeline = new CopyPipeline(this.device);
this.resize(size);
this.size = size;
this.texture = this.createTexture(size);
this.textureView = this.texture.createView();
}
public resize(size: vec2): void {
if (this.size !== null && vec2.equals(this.size, size)) {
if (vec2.equals(this.size, size)) {
return;
}
const newTexture = this.device.createTexture({
format: 'rgba16float',
size: {
width: size[0],
height: size[1],
},
usage:
GPUTextureUsage.STORAGE_BINDING |
GPUTextureUsage.TEXTURE_BINDING |
GPUTextureUsage.RENDER_ATTACHMENT,
});
const newTexture = this.createTexture(size);
const newTextureView = newTexture.createView();
if (this.size) {
const commandEncoder = this.device.createCommandEncoder();
this.copyPipeline.execute(
commandEncoder,
this.textureView,
newTextureView,
vec2.div(vec2.create(), this.size, size)
);
this.device.queue.submit([commandEncoder.finish()]);
this.texture.destroy();
}
const commandEncoder = this.device.createCommandEncoder();
this.copyPipeline.execute(
commandEncoder,
this.textureView,
newTextureView,
vec2.div(vec2.create(), this.size, size)
);
this.device.queue.submit([commandEncoder.finish()]);
this.texture.destroy();
this.size = size;
this.texture = newTexture;
@ -60,4 +49,15 @@ export class ResizableTexture {
this.texture.destroy();
this.copyPipeline.destroy();
}
private createTexture(size: vec2): GPUTexture {
return this.device.createTexture({
format: 'rgba16float',
size: { width: size[0], height: size[1] },
usage:
GPUTextureUsage.STORAGE_BINDING |
GPUTextureUsage.TEXTURE_BINDING |
GPUTextureUsage.RENDER_ATTACHMENT,
});
}
}