From c9a0fc2a0c3ef1e01a18121a87cd29efae645f68 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Sat, 13 May 2023 13:21:58 +0800 Subject: [PATCH] fix(destroy): destroy has bug (#142) fix destroy buffer fix destroy texture fix destroy object3D fix destroy geometry fix destroy material fix destroy component --- samples/base/Sample_AddRemove.ts | 80 +++++++++++++++++++ samples/lights/Sample_PointLight.ts | 1 + src/components/Transform.ts | 43 +++++++--- src/components/renderer/MeshRenderer.ts | 8 ++ src/components/renderer/RenderNode.ts | 8 ++ src/core/bound/BoundingBox.ts | 11 +++ src/core/entities/Entity.ts | 6 +- src/core/geometry/GeometryBase.ts | 20 +++++ src/core/geometry/GeometryIndicesBuffer.ts | 10 +++ src/core/geometry/GeometryVertexBuffer.ts | 12 +++ src/core/pool/memory/MemoryInfo.ts | 8 ++ .../webGpu/core/buffer/GPUBufferBase.ts | 27 ++++++- .../graphics/webGpu/shader/ComputeShader.ts | 64 +++++++-------- src/gfx/graphics/webGpu/shader/ShaderBase.ts | 27 +++++-- .../cluster/ClusterLightingRender.ts | 17 +++- src/materials/LitMaterial.ts | 4 + src/materials/MaterialPass.ts | 8 +- src/materials/PhysicMaterial.ts | 11 ++- 18 files changed, 302 insertions(+), 63 deletions(-) create mode 100644 samples/base/Sample_AddRemove.ts diff --git a/samples/base/Sample_AddRemove.ts b/samples/base/Sample_AddRemove.ts new file mode 100644 index 00000000..1a20c139 --- /dev/null +++ b/samples/base/Sample_AddRemove.ts @@ -0,0 +1,80 @@ +import { Engine3D, Scene3D, CameraUtil, View3D, AtmosphericComponent, ComponentBase, Time, AxisObject, Object3DUtil, KelvinUtil, DirectLight, Object3D, HoverCameraController, MeshRenderer, LitMaterial, BoxGeometry, UnLit, UnLitMaterial, Interpolator } from "@orillusion/core"; +import { GUIHelp } from "@orillusion/debug/GUIHelp"; + +// sample use component +class Sample_AddRemove { + view: View3D; + async run() { + // init engine + await Engine3D.init(); + // create new Scene + let scene = new Scene3D(); + // add atmospheric sky + scene.addComponent(AtmosphericComponent); + + // init camera3D + let mainCamera = CameraUtil.createCamera3D(null, scene); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); + let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); + hoverCameraController.setCamera(15, -30, 300); + + // create a view with target scene and camera + this.view = new View3D(); + this.view.scene = scene; + this.view.camera = mainCamera; + + // start render + Engine3D.startRenderView(this.view); + + // gui + GUIHelp.init(); + + await this.test(); + } + + private test() { + let list: Object3D[] = []; + let index = 0; + GUIHelp.addButton("add", async () => { + // let obj = new Object3D(); + // obj.z += index++ * 1; + // obj.x = Math.random() * 100 - 50 + // obj.y = Math.random() * 100 - 50 + // obj.z = Math.random() * 100 - 50 + // let mr = obj.addComponent(MeshRenderer); + // mr.material = new LitMaterial(); + // mr.geometry = new BoxGeometry(10, 10, 10); + // this.view.scene.addChild(obj); + + /******** player1 *******/ + let player1 = (await Engine3D.res.loadGltf('gltfs/anim/Minion_Lane_Super_Dawn/Minion_Lane_Super_Dawn.glb', {})) as Object3D; + player1.transform.scaleX = 10; + player1.transform.scaleY = 10; + player1.transform.scaleZ = 10; + + let cc = player1.clone(); + this.view.scene.addChild(cc); + list.push(cc); + + // Interpolator.to(cc, { z: 100, scaleX: 5, scaleY: 5, scaleZ: 5 }, 1000).onComplete = () => { + // this.view.scene.removeChild(cc); + // let index = list.indexOf(cc); + // list.splice(index, 1); + // }; + }); + + GUIHelp.addButton("remove", () => { + let index = Math.floor(list.length * Math.random()); + let obj = list[index]; + if (obj) { + console.log(index, list); + list.splice(index, 1); + obj.destroy(); + } + }); + + GUIHelp.endFolder(); + } +} + +new Sample_AddRemove().run(); \ No newline at end of file diff --git a/samples/lights/Sample_PointLight.ts b/samples/lights/Sample_PointLight.ts index 24ed0a25..d1a7c759 100644 --- a/samples/lights/Sample_PointLight.ts +++ b/samples/lights/Sample_PointLight.ts @@ -29,6 +29,7 @@ class Sample_PointLight { view.camera = mainCamera; Engine3D.startRenderViews([view]); + } public debug(light: PointLight) { diff --git a/src/components/Transform.ts b/src/components/Transform.ts index b7497b11..0f197bf3 100644 --- a/src/components/Transform.ts +++ b/src/components/Transform.ts @@ -125,7 +125,7 @@ export class Transform extends ComponentBase { } this.object3D.entityChildren.forEach((v) => { - v.transform.parent = this; + v.transform.parent = value ? this : null; }); } @@ -414,17 +414,7 @@ export class Transform extends ComponentBase { } } - destroy(): void { - if (this.parent && this.parent.object3D) { - this.parent.object3D.removeChild(this.object3D); - this.scene3D = null; - this.localPosition = null; - this.localRotQuat = null; - this.localRotation = null; - this.localScale = null; - } - super.destroy(); - } + public decomposeFromMatrix(matrix: Matrix4, orientationStyle: string = 'eulerAngles'): this { @@ -715,6 +705,35 @@ export class Transform extends ComponentBase { return this._localScale; } + destroy(): void { + if (this.parent && this.parent.object3D) { + this.parent.object3D.removeChild(this.object3D); + this.scene3D = null; + } + super.destroy(); + + this.eventPositionChange = null; + this.eventRotationChange = null; + this.eventScaleChange = null; + this.onPositionChange = null; + this.onRotationChange = null; + this.onScaleChange = null; + this._scene3d = null; + this._parent = null; + this._localPos = null; + this._localRot = null; + this._localRotQuat = null; + this._localScale = null; + this._forward = null; + this._back = null; + this._right = null; + this._left = null; + this._up = null; + this._down = null; + this._localChange = null; + this._targetPos = null; + } + // private _rotateAroundAxisX:number = 0 ; // public set rotateAroundAxisX(value:number){ // this._rotateAroundAxisX = value; diff --git a/src/components/renderer/MeshRenderer.ts b/src/components/renderer/MeshRenderer.ts index 80ef70b0..06c161b9 100644 --- a/src/components/renderer/MeshRenderer.ts +++ b/src/components/renderer/MeshRenderer.ts @@ -125,6 +125,14 @@ export class MeshRenderer extends RenderNode { super.nodeUpdate(view, passType, renderPassState, clusterLightingBuffer); } + public destroy(): void { + this.geometry.destroy(); + this.materials.forEach(mat => { + mat.destroy(); + }); + super.destroy(); + } + cloneTo(obj: Object3D) { let mr = obj.addComponent(MeshRenderer); mr.geometry = this.geometry; diff --git a/src/components/renderer/RenderNode.ts b/src/components/renderer/RenderNode.ts index 5ecffb53..4a36a099 100644 --- a/src/components/renderer/RenderNode.ts +++ b/src/components/renderer/RenderNode.ts @@ -433,4 +433,12 @@ export class RenderNode extends ComponentBase { } } + public destroy() { + super.destroy(); + + this._geometry = null; + this._materials = null; + this._combineShaderRefection = null; + } + } diff --git a/src/core/bound/BoundingBox.ts b/src/core/bound/BoundingBox.ts index edc43e70..3bec5ed0 100644 --- a/src/core/bound/BoundingBox.ts +++ b/src/core/bound/BoundingBox.ts @@ -10,6 +10,7 @@ import { Vector3 } from '../../math/Vector3'; * @group Core */ export class BoundingBox implements IBound { + /** * The center of the bounding box. */ @@ -167,4 +168,14 @@ export class BoundingBox implements IBound { public updateBound() { } + + public destroy() { + this.center = null; + this.extents = null; + this.min = null; + this.max = null; + this.size = null; + this.worldMax = null; + this.worldMin = null; + } } diff --git a/src/core/entities/Entity.ts b/src/core/entities/Entity.ts index e696ca77..b76ca6ab 100644 --- a/src/core/entities/Entity.ts +++ b/src/core/entities/Entity.ts @@ -368,10 +368,14 @@ export class Entity extends CEventDispatcher { * release current object */ public destroy() { - this.transform.parent = null; this.components.forEach((c) => { c.destroy(); }); this.components.clear(); + this.entityChildren.forEach((c) => { + c.destroy(); + }) + this.transform.parent = null; + // this.entityChildren = null; } } diff --git a/src/core/geometry/GeometryBase.ts b/src/core/geometry/GeometryBase.ts index b40b2ad8..8e404022 100644 --- a/src/core/geometry/GeometryBase.ts +++ b/src/core/geometry/GeometryBase.ts @@ -30,6 +30,7 @@ export class SubGeometry { * @group Geometry */ export class GeometryBase { + public uuid: string; public name: string; public subGeometries: SubGeometry[] = []; @@ -263,4 +264,23 @@ export class GeometryBase { public isPrimitive(): boolean { return false;// this.geometrySource != null && this.geometrySource.type != 'none'; } + + destroy() { + this.uuid = null; + this.name = null; + this.subGeometries = null; + this.morphTargetDictionary = null; + + this._bounds.destroy(); + this._bounds = null; + + this._attributeMap = null; + this._attributes = null; + + this._indicesBuffer.destroy(); + this._vertexBuffer.destroy(); + + this._indicesBuffer = null; + this._vertexBuffer = null; + } } diff --git a/src/core/geometry/GeometryIndicesBuffer.ts b/src/core/geometry/GeometryIndicesBuffer.ts index 350a9650..b496817c 100644 --- a/src/core/geometry/GeometryIndicesBuffer.ts +++ b/src/core/geometry/GeometryIndicesBuffer.ts @@ -4,6 +4,7 @@ import { VertexAttributeData } from "./VertexAttributeData"; export class GeometryIndicesBuffer { + public uuid: string = ''; public name: string; public indicesGPUBuffer: IndicesGPUBuffer; @@ -31,6 +32,15 @@ export class GeometryIndicesBuffer { } + destroy() { + this.uuid = null; + this.name = null; + this.indicesFormat = null; + this.indicesCount = null; + this.indicesGPUBuffer.destroy(); + this.indicesGPUBuffer = null; + } + /** * Get indices from geometry data * Get position attribute from geometry data diff --git a/src/core/geometry/GeometryVertexBuffer.ts b/src/core/geometry/GeometryVertexBuffer.ts index 762514fe..8be8e2d9 100644 --- a/src/core/geometry/GeometryVertexBuffer.ts +++ b/src/core/geometry/GeometryVertexBuffer.ts @@ -7,6 +7,7 @@ import { VertexAttributeSize } from "./VertexAttributeSize"; export class GeometryVertexBuffer { + public vertexCount: number = 0; public vertexGPUBuffer: VertexGPUBuffer; public geometryType: GeometryVertexType = GeometryVertexType.compose; @@ -190,4 +191,15 @@ export class GeometryVertexBuffer { public compute() { } + + public destroy() { + this.vertexCount = null; + this.geometryType = null; + this._vertexBufferLayouts = null; + this._attributeSlotLayouts = null; + this._attributeLocation = null; + + this.vertexGPUBuffer.destroy(); + this.vertexGPUBuffer = null; + } } \ No newline at end of file diff --git a/src/core/pool/memory/MemoryInfo.ts b/src/core/pool/memory/MemoryInfo.ts index aff62e83..14d8bc8a 100644 --- a/src/core/pool/memory/MemoryInfo.ts +++ b/src/core/pool/memory/MemoryInfo.ts @@ -9,6 +9,7 @@ import { Vector4 } from '../../../math/Vector4'; * @group Core */ export class MemoryInfo { + public byteOffset: number; public byteSize: number; public offset: number = 0; @@ -367,4 +368,11 @@ export class MemoryInfo { public reset() { this.offset = 0; } + + destroy() { + this.byteOffset = null; + this.byteSize = null; + this.offset = null; + this.dataBytes = null; + } } diff --git a/src/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts b/src/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts index b169da0f..b03ab6c3 100644 --- a/src/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts +++ b/src/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts @@ -294,9 +294,32 @@ export class GPUBufferBase { } public destroy() { + if (this.memoryNodes) { + this.memoryNodes.forEach((v) => { + v.destroy(); + }) + } + + this.bufferType = null; + this.seek = null; + this.byteSize = null; + this.usage = null; + this.visibility = null; + this.outFloat32Array = null; - this.buffer.destroy(); - this.memory.destroy(); + if (this.buffer) { + this.buffer.destroy(); + } + this.buffer = null; + + if (this.memory) { + this.memory.destroy(); + } + this.memory = null; + + if (this._readBuffer) { + this._readBuffer.destroy(); + } } protected createBuffer(usage: GPUBufferUsageFlags, size: number, data?: ArrayBufferData) { diff --git a/src/gfx/graphics/webGpu/shader/ComputeShader.ts b/src/gfx/graphics/webGpu/shader/ComputeShader.ts index 9bea1446..bbd44c2d 100644 --- a/src/gfx/graphics/webGpu/shader/ComputeShader.ts +++ b/src/gfx/graphics/webGpu/shader/ComputeShader.ts @@ -3,6 +3,10 @@ import { webGPUContext } from '../Context3D'; import { ShaderBase } from './ShaderBase'; import { ShaderReflection, ShaderReflectionVarInfo } from './value/ShaderReflectionInfo'; import { Preprocessor } from './util/Preprocessor'; +import { Struct } from '../../../..'; +import { StorageGPUBuffer } from '../core/buffer/StorageGPUBuffer'; +import { StructStorageGPUBuffer } from '../core/buffer/StructStorageGPUBuffer'; +import { UniformGPUBuffer } from '../core/buffer/UniformGPUBuffer'; /** * @internal @@ -37,6 +41,7 @@ export class ComputeShader extends ShaderBase { private _storageTextureDic: Map; private _sampleTextureDic: Map; private _groupsShaderReflectionVarInfos: ShaderReflectionVarInfo[][]; + private _groupCache: { [name: string]: { groupIndex: number, infos: any } } = {}; /** * @@ -73,6 +78,8 @@ export class ComputeShader extends ShaderBase { // } } + + /** * Record the compute shader distribution command * @param computePass Compute pass encoder @@ -96,7 +103,28 @@ export class ComputeShader extends ShaderBase { } } - public readHeap() { + private createBufferBindGroup(groupIndex: number, varName: string, binding: number, entries: GPUBindGroupEntry[]) { + let buffer = this._bufferDic.get(varName); + if (buffer) { + let entry: GPUBindGroupEntry = { + binding: binding, + resource: { + buffer: buffer.buffer, + offset: 0,//buffer.memory.shareFloat32Array.byteOffset, + size: buffer.memory.shareDataBuffer.byteLength, + }, + } + entries.push(entry); + } else { + console.error(`ComputeShader(${this.instanceID})`, `buffer ${varName} is missing!`); + } + } + + protected noticeBufferChange(name: string) { + let bindGroupCache = this._groupCache[name]; + if (bindGroupCache) { + this.genGroups(bindGroupCache.groupIndex, bindGroupCache.infos, true); + } } protected genGroups(groupIndex: number, infos: ShaderReflectionVarInfo[][], force: boolean = false) { @@ -110,40 +138,11 @@ export class ComputeShader extends ShaderBase { switch (refs.varType) { case `uniform`: - { - let buffer = this._bufferDic.get(refs.varName); - if (buffer) { - let entry: GPUBindGroupEntry = { - binding: refs.binding, - resource: { - buffer: buffer.buffer, - offset: 0, //buffer.memory.shareFloat32Array.byteOffset, - size: buffer.memory.shareDataBuffer.byteLength, - }, - } - entries.push(entry); - } else { - console.error(`ComputeShader(${this.instanceID})`, `buffer ${refs.varName} is missing!`); - } - } - break; case `storage-read`: case `storage-read_write`: { - let buffer = this._bufferDic.get(refs.varName); - if (buffer) { - let entry: GPUBindGroupEntry = { - binding: refs.binding, - resource: { - buffer: buffer.buffer, - offset: 0,//buffer.memory.shareFloat32Array.byteOffset, - size: buffer.memory.shareDataBuffer.byteLength, - }, - } - entries.push(entry); - } else { - console.error(`ComputeShader(${this.instanceID})`, `buffer ${refs.varName} is missing!`); - } + this.createBufferBindGroup(groupIndex, refs.varName, refs.binding, entries); + this._groupCache[refs.varName] = { groupIndex: groupIndex, infos: infos }; } break; case `var`: @@ -207,6 +206,7 @@ export class ComputeShader extends ShaderBase { layout: this._computePipeline.getBindGroupLayout(groupIndex), entries: entries }); + this.bindGroups[groupIndex] = gpubindGroup; } } diff --git a/src/gfx/graphics/webGpu/shader/ShaderBase.ts b/src/gfx/graphics/webGpu/shader/ShaderBase.ts index 3f36ac8a..162617a0 100644 --- a/src/gfx/graphics/webGpu/shader/ShaderBase.ts +++ b/src/gfx/graphics/webGpu/shader/ShaderBase.ts @@ -85,12 +85,15 @@ export class ShaderBase { } /** - * set storage gpu buffer - * @param name buffer name - * @param buffer storage useAge gpu buffer - */ +* set storage gpu buffer +* @param name buffer name +* @param buffer storage useAge gpu buffer +*/ public setStorageBuffer(name: string, buffer: StorageGPUBuffer) { - if (!this._bufferDic.has(name)) { + if (this._bufferDic.has(name)) { + this._bufferDic.set(name, buffer); + this.noticeBufferChange(name); + } else { this._bufferDic.set(name, buffer); } } @@ -101,7 +104,10 @@ export class ShaderBase { * @param buffer struct storage useAge gpu buffer */ public setStructStorageBuffer(name: string, buffer: StructStorageGPUBuffer) { - if (!this._bufferDic.has(name)) { + if (this._bufferDic.has(name)) { + this._bufferDic.set(name, buffer); + this.noticeBufferChange(name); + } else { this._bufferDic.set(name, buffer); } } @@ -112,7 +118,10 @@ export class ShaderBase { * @param buffer */ public setUniformBuffer(name: string, buffer: UniformGPUBuffer) { - if (!this._bufferDic.has(name)) { + if (this._bufferDic.has(name)) { + this._bufferDic.set(name, buffer); + this.noticeBufferChange(name); + } else { this._bufferDic.set(name, buffer); } } @@ -224,6 +233,10 @@ export class ShaderBase { } } + protected noticeBufferChange(name: string) { + + } + /** * destroy */ diff --git a/src/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts b/src/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts index 32f2c745..04ed3df6 100644 --- a/src/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts +++ b/src/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts @@ -20,13 +20,14 @@ export class ClusterLightingRender extends RendererBase { public clusterTileY = 9; public clusterTileZ = 16; public maxNumLights = 128; - public maxNumLightsPerCluster = 100; + public maxNumLightsPerCluster = 1024; public clusterPix = 1; public clusterLightingBuffer: ClusterLightingBuffer; private _currentLightCount = 0; private _clusterGenerateCompute: ComputeShader; private _clusterLightingCompute: ComputeShader; + useCamera: import("c:/work/git/orillusion-nian/src/index").Camera3D; constructor(view: View3D) { super(); @@ -48,9 +49,9 @@ export class ClusterLightingRender extends RendererBase { this.clusterLightingBuffer = new ClusterLightingBuffer(numClusters, this.maxNumLightsPerCluster); this.clusterLightingBuffer.update(size[0], size[1], this.clusterPix, this.clusterTileX, this.clusterTileY, this.clusterTileZ, this.maxNumLights, this.maxNumLightsPerCluster, near, far); - let standBindGroup = GlobalBindGroup.getCameraGroup(camera); - this._clusterGenerateCompute.setUniformBuffer(`globalUniform`, standBindGroup.uniformGPUBuffer); - this._clusterLightingCompute.setUniformBuffer(`globalUniform`, standBindGroup.uniformGPUBuffer); + // let standBindGroup = GlobalBindGroup.getCameraGroup(camera); + // this._clusterGenerateCompute.setUniformBuffer(`globalUniform`, standBindGroup.uniformGPUBuffer); + // this._clusterLightingCompute.setUniformBuffer(`globalUniform`, standBindGroup.uniformGPUBuffer); this._clusterGenerateCompute.setUniformBuffer(`clustersUniform`, this.clusterLightingBuffer.clustersUniformBuffer); this._clusterGenerateCompute.setStorageBuffer(`clusterBuffer`, this.clusterLightingBuffer.clusterBuffer); @@ -67,8 +68,16 @@ export class ClusterLightingRender extends RendererBase { let scene = view.scene; let lights: ILight[] = EntityCollect.instance.getLights(scene); + if (this.useCamera != view.camera) { + this.useCamera = view.camera; + let standBindGroup = GlobalBindGroup.getCameraGroup(this.useCamera); + this._clusterGenerateCompute.setUniformBuffer(`globalUniform`, standBindGroup.uniformGPUBuffer); + this._clusterLightingCompute.setUniformBuffer(`globalUniform`, standBindGroup.uniformGPUBuffer); + } + if (this._currentLightCount != lights.length) { this._currentLightCount = lights.length; + this.clusterLightingBuffer.clustersUniformBuffer.setFloat('numLights', lights.length); this.clusterLightingBuffer.clustersUniformBuffer.apply(); diff --git a/src/materials/LitMaterial.ts b/src/materials/LitMaterial.ts index ff4164da..025d0294 100644 --- a/src/materials/LitMaterial.ts +++ b/src/materials/LitMaterial.ts @@ -81,6 +81,10 @@ export class LitMaterial extends PhysicMaterial { */ debug() { } + + public destroy(): void { + super.destroy(); + } } registerMaterial("LitMaterial", LitMaterial); diff --git a/src/materials/MaterialPass.ts b/src/materials/MaterialPass.ts index fad9bb37..5edf81b2 100644 --- a/src/materials/MaterialPass.ts +++ b/src/materials/MaterialPass.ts @@ -144,13 +144,15 @@ export class MaterialPass { * release material pass */ public destroy() { - this.renderShader.destroy(); + if (this.renderShader) { + this.renderShader.destroy(); + } this.renderShader = null; - this.renderPasses.forEach((v, k) => { for (let i = 0; i < v.length; i++) { const pass = v[i]; - pass.destroy(); + if (pass != this) + pass.destroy(); } v.length = 0; }); diff --git a/src/materials/PhysicMaterial.ts b/src/materials/PhysicMaterial.ts index 6aa96a96..89a6d632 100644 --- a/src/materials/PhysicMaterial.ts +++ b/src/materials/PhysicMaterial.ts @@ -345,10 +345,17 @@ export class PhysicMaterial extends MaterialBase { return this.renderShader.uniforms[`clearcoatColor`].color; } + public destroy(): void { + if (this.baseMap || (this.baseMap.name != "" && this.baseMap.name.indexOf("defaultOri") == -1)) { + this.baseMap.destroy(); + } - public debug() { - + if (this.normalMap || (this.normalMap.name != "" && this.normalMap.name.indexOf("defaultOri") == -1)) { + this.normalMap.destroy(); + } + super.destroy(); } + } registerMaterial("PhysicMaterial", PhysicMaterial); \ No newline at end of file