124 lines
3 KiB
TypeScript
124 lines
3 KiB
TypeScript
import { vec2 } from 'gl-matrix';
|
|
|
|
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 clearValue: GPUColor;
|
|
private readonly format: GPUTextureFormat;
|
|
private readonly usage: GPUTextureUsageFlags;
|
|
|
|
public constructor(
|
|
private readonly device: GPUDevice,
|
|
size: vec2,
|
|
{
|
|
clearValue = { r: 0, g: 0, b: 0, a: 0 },
|
|
format = TRAIL_SOURCE_TEXTURE_FORMAT,
|
|
usage = defaultTextureUsage,
|
|
}: ResizableTextureOptions = {}
|
|
) {
|
|
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 prepareResize(size: vec2): PendingTextureResize | null {
|
|
if (vec2.equals(this.size, size)) {
|
|
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]),
|
|
};
|
|
|
|
return {
|
|
copySize,
|
|
newSize: vec2.clone(size),
|
|
newTexture,
|
|
newTextureView,
|
|
oldTexture: this.texture,
|
|
};
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
private createTexture(size: vec2): GPUTexture {
|
|
return this.device.createTexture({
|
|
format: this.format,
|
|
size: { width: size[0], height: size[1] },
|
|
usage: this.usage,
|
|
});
|
|
}
|
|
}
|
|
|
|
const defaultTextureUsage =
|
|
GPUTextureUsage.STORAGE_BINDING |
|
|
GPUTextureUsage.TEXTURE_BINDING |
|
|
GPUTextureUsage.RENDER_ATTACHMENT |
|
|
GPUTextureUsage.COPY_SRC |
|
|
GPUTextureUsage.COPY_DST;
|