UNPKG

xgpu

Version:

XGPU is an extendable library for WebGPU that provides a higher-level, easy-to-use interface for building rendering engines or processing numeric data. It handles automatic data binding, buffer alignment, variable declarations in shaders, and more. XGPU i

128 lines (127 loc) 5.11 kB
// Copyright (c) 2023 Thomas Le Coz. All rights reserved. // This code is governed by an MIT license that can be found in the LICENSE file. import { XGPU } from "./XGPU"; import { RenderPipeline } from "./pipelines/RenderPipeline"; import { Texture } from "./pipelines/resources/textures/Texture"; export class TextureRenderer { textureObj; dimensionChanged = false; currentWidth; currentHeight; renderPipelines = []; useTextureInComputeShader; frameId = -1; constructor(useTextureInComputeShader = false) { this.useTextureInComputeShader = useTextureInComputeShader; } deviceId; init(w, h, usage, sampleCount) { this.currentWidth = w; this.currentHeight = h; return new Promise((onResolve) => { XGPU.init().then(() => { this.deviceId = XGPU.deviceId; if (!usage) usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC; let format = "bgra8unorm"; if (this.useTextureInComputeShader) { format = "rgba8unorm"; usage += GPUTextureUsage.STORAGE_BINDING; } this.textureObj = new Texture({ size: [w, h], format, usage, sampleCount }); this.textureObj.create(); onResolve(this); }); }); } //public get firstPipeline(): RenderPipeline { return this.renderPipelines[0]; } nbColorAttachment = 0; addPipeline(pipeline, offset = null) { pipeline.renderer = this; if (pipeline.renderPassDescriptor.colorAttachments[0]) this.nbColorAttachment++; if (offset === null) this.renderPipelines.push(pipeline); else this.renderPipelines.splice(offset, 0, pipeline); return pipeline; } removePipeline(pipeline) { if (pipeline.renderPassDescriptor.colorAttachments[0]) this.nbColorAttachment--; const id = this.renderPipelines.indexOf(pipeline); if (id != -1) { this.renderPipelines.splice(id, 1); } pipeline.renderer = null; return pipeline; } //public get nbPipeline(): number { return this.renderPipelines.length } //public get useSinglePipeline(): boolean { return this.nbColorAttachment === 1 } resize(w, h) { this.currentWidth = w; this.currentHeight = h; this.dimensionChanged = true; if (this.textureObj) this.textureObj.resize(w, h); } destroy() { for (let i = 0; i < this.renderPipelines.length; i++) { this.renderPipelines[i].destroy(); } this.renderPipelines = []; for (let z in this) { this[z] = null; } } commandEncoder = null; async update() { if (!XGPU.ready || this.renderPipelines.length === 0 || this.deviceId === undefined) return; let deviceChanged = XGPU.deviceId != this.deviceId; if (deviceChanged) { if (this.textureObj) this.textureObj.create(); this.deviceId = XGPU.deviceId; for (let i = 0; i < this.renderPipelines.length; i++) { this.renderPipelines[i].clearAfterDeviceLostAndRebuild(); } } this.commandEncoder = XGPU.device.createCommandEncoder(); let pipeline, renderPass; for (let i = 0; i < this.renderPipelines.length; i++) { pipeline = this.renderPipelines[i]; pipeline.update(); for (let j = 0; j < pipeline.pipelineCount; j++) { renderPass = pipeline.beginRenderPass(this.commandEncoder, this.view, j); pipeline.dispatchEvent(RenderPipeline.ON_DRAW, j); //if (pipeline.onDraw) pipeline.onDraw(j); pipeline.draw(renderPass); pipeline.end(this.commandEncoder, renderPass); } } const commandBuffer = this.commandEncoder.finish(); this.commandEncoder = null; XGPU.device.queue.submit([commandBuffer]); this.dimensionChanged = false; } get resized() { return this.dimensionChanged; } get canvas() { return null; } get width() { return this.currentWidth; } get height() { return this.currentHeight; } get texture() { if (!this.textureObj) throw new Error("TextureRenderer is not initialized yet. You must Use TextureRenderer.init in order to initialize it"); return this.textureObj.gpuResource; } get view() { if (!this.textureObj) throw new Error("TextureRenderer is not initialized yet. You must Use TextureRenderer.init in order to initialize it"); return this.textureObj.view; } }