Skip to content

Commit

Permalink
[Update] RecyclePool (#176)
Browse files Browse the repository at this point in the history
  • Loading branch information
GengineJS authored Sep 18, 2023
1 parent 36a8efb commit ed1652b
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 82 deletions.
28 changes: 2 additions & 26 deletions cocos/core/memop/recycle-pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@

import { ScalableContainer } from './scalable-container';

export class UpdateRecyclePool {
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type, @typescript-eslint/no-empty-function
update (...args: any[]) {}
}

/**
* @en Recyclable object pool. It's designed to be entirely reused each time.
* There is no put and get method, each time you get the [[data]], you can use all elements as new.
Expand All @@ -41,7 +36,7 @@ export class UpdateRecyclePool {
* @see [[Pool]]
*/
export class RecyclePool<T = any> extends ScalableContainer {
private _fn: (...args: any[]) => T;
private _fn: () => T;
private _dtor: ((obj: T) => void) | null = null;
private _count = 0;
private _data: T[];
Expand All @@ -54,7 +49,7 @@ export class RecyclePool<T = any> extends ScalableContainer {
* @param size Initial pool size
* @param dtor The finalizer of element, it's invoked when this container is destroyed or shrunk
*/
constructor (fn: (...args: any[]) => T, size: number, dtor?: (obj: T) => void) {
constructor (fn: () => T, size: number, dtor?: (obj: T) => void) {
super();
this._fn = fn;
this._dtor = dtor || null;
Expand Down Expand Up @@ -115,25 +110,6 @@ export class RecyclePool<T = any> extends ScalableContainer {
return this._data[this._count++];
}

/**
* @en Create objects with given parameters. If object creation is parameter-based, it is recommended to start with an initial length of 0.
* @zh 通过给定参数构建对象,如果是通过参数构建对象的方式,建议Pool初始长度为0,并让目标类继承UpdateRecyclePool,便于更新操作。
*/
public addWithArgs (...args: any[]): T {
const data = this._data[this._count];
if (data) {
this._count++;
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
if (data instanceof UpdateRecyclePool) { data.update(...args); }
return data;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
const newObj = this._fn(...args); // 使用传入的参数创建新对象
this._data[this._count++] = newObj;

return newObj;
}

/**
* @en Destroy the object pool. Please don't use it any more after it is destroyed.
* @zh 销毁对象池。销毁后不能继续使用。
Expand Down
8 changes: 4 additions & 4 deletions cocos/rendering/custom/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1664,19 +1664,19 @@ class ExecutorPools {
}), 64);
}
addDeviceQueue (): DeviceRenderQueue {
return this.deviceQueuePool.addWithArgs();
return this.deviceQueuePool.add();
}
addComputeQueue (): DeviceComputeQueue {
return this.computeQueuePool.add();
}
addGraphScene (): GraphScene {
return this.graphScenePool.addWithArgs();
return this.graphScenePool.add();
}
addReflectionProbe (): RenderReflectionProbeQueue {
return this.reflectionProbe.addWithArgs();
return this.reflectionProbe.add();
}
addRasterPassInfo (): RasterPassInfo {
return this.rasterPassInfoPool.addWithArgs();
return this.rasterPassInfoPool.add();
}
addComputePassInfo (): ComputePassInfo {
return this.computePassInfoPool.add();
Expand Down
68 changes: 34 additions & 34 deletions cocos/rendering/custom/scene-culling.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Vec3, assert, RecyclePool, UpdateRecyclePool, cclegacy } from '../../core';
import { Vec3, assert, RecyclePool } from '../../core';
import { Frustum, intersect, AABB } from '../../core/geometry';
import { CommandBuffer } from '../../gfx';
import { BatchingSchemes, IMacroPatch, Pass, RenderScene } from '../../render-scene';
import { CSMLevel, Camera, DirectionalLight, Light, LightType, Model, ProbeType,
ReflectionProbe, SKYBOX_FLAG, ShadowType, SpotLight, SubModel } from '../../render-scene/scene';
import { BatchingSchemes, Pass, RenderScene } from '../../render-scene';
import { CSMLevel, Camera, DirectionalLight, LightType, Model, ProbeType,
ReflectionProbe, SKYBOX_FLAG, ShadowType, SpotLight } from '../../render-scene/scene';
import { Layers, Node } from '../../scene-graph';
import { PipelineSceneData } from '../pipeline-scene-data';
import { hashCombineStr, getSubpassOrPassID, bool } from './define';
Expand All @@ -14,19 +14,12 @@ import { RenderQueue, RenderQueueDesc, instancePool } from './web-pipeline-types
import { ObjectPool } from './utils';

const vec3Pool = new ObjectPool(() => new Vec3());
const cullingKeyRecycle = new RecyclePool((
sceneData: SceneData,
castShadows: boolean,
sceneId: number,
) => new CullingKey(sceneData, castShadows, sceneId), 0);
const cullingQueriesRecycle = new RecyclePool(() => new CullingQueries(), 0);
const renderQueueRecycle = new RecyclePool(() => new RenderQueue(), 0);
const renderQueueDescRecycle = new RecyclePool((
culledSource: number,
renderQueueTarget: number,
lightType: LightType,
) => new RenderQueueDesc(culledSource, renderQueueTarget, lightType), 0);

class CullingPools {
cullingKeyRecycle = new RecyclePool(() => new CullingKey(), 8);
cullingQueriesRecycle = new RecyclePool(() => new CullingQueries(), 8);
renderQueueRecycle = new RecyclePool(() => new RenderQueue(), 8);
renderQueueDescRecycle = new RecyclePool(() => new RenderQueueDesc(), 8);
}
const REFLECTION_PROBE_DEFAULT_MASK = Layers.makeMaskExclude([Layers.BitMask.UI_2D, Layers.BitMask.UI_3D,
Layers.BitMask.GIZMOS, Layers.BitMask.EDITOR,
Layers.BitMask.SCENE_GIZMO, Layers.BitMask.PROFILER]);
Expand Down Expand Up @@ -82,23 +75,22 @@ function computeCullingKey (
return hashCode;
}

class CullingKey extends UpdateRecyclePool {
sceneData: SceneData;
class CullingKey {
sceneData: SceneData | null = null;
castShadows = false;
constructor (sceneData: SceneData, castShadows: boolean, verId: number) {
super();
constructor (sceneData: SceneData | null = null, castShadows: boolean = false) {
this.sceneData = sceneData;
this.castShadows = castShadows;
}
update (sceneData: SceneData, castShadows: boolean, verId: number): void {
update (sceneData: SceneData, castShadows: boolean): void {
this.sceneData = sceneData;
this.castShadows = castShadows;
}
}

let pSceneData: PipelineSceneData;

class CullingQueries extends UpdateRecyclePool {
class CullingQueries {
// key: hash val
culledResultIndex: Map<number, number> = new Map<number, number>();
cullingKeyResult: Map<number, CullingKey> = new Map<number, CullingKey>();
Expand Down Expand Up @@ -274,17 +266,18 @@ export class SceneCulling {
culledResults: Array<Array<Model>> = new Array<Array<Model>>();
renderQueues: Array<RenderQueue> = new Array<RenderQueue>();
sceneQueryIndex: Map<number, RenderQueueDesc> = new Map<number, RenderQueueDesc>();
cullingPools = new CullingPools();
// source id
numCullingQueries = 0;
// target id
numRenderQueues = 0;
layoutGraph;
renderGraph;
resetPool (): void {
cullingKeyRecycle.reset();
cullingQueriesRecycle.reset();
renderQueueRecycle.reset();
renderQueueDescRecycle.reset();
this.cullingPools.cullingKeyRecycle.reset();
this.cullingPools.cullingQueriesRecycle.reset();
this.cullingPools.renderQueueRecycle.reset();
this.cullingPools.renderQueueDescRecycle.reset();
instancePool.reset();
}
clear (): void {
Expand All @@ -311,7 +304,9 @@ export class SceneCulling {
const scene = sceneData.scene!;
let queries = this.sceneQueries.get(scene);
if (!queries) {
this.sceneQueries.set(scene, cullingQueriesRecycle.addWithArgs());
const cullingQuery = this.cullingPools.cullingQueriesRecycle.add();
cullingQuery.update();
this.sceneQueries.set(scene, cullingQuery);
queries = this.sceneQueries.get(scene);
}
const castShadow: boolean = bool(sceneData.flags & SceneFlags.SHADOW_CASTER);
Expand All @@ -326,19 +321,22 @@ export class SceneCulling {
this.culledResults.push([]);
}
queries!.culledResultIndex.set(key, sourceID);
queries!.cullingKeyResult.set(key, cullingKeyRecycle.addWithArgs(
const cullingKey = this.cullingPools.cullingKeyRecycle.add();
cullingKey.update(
sceneData,
castShadow,
sceneId,
));
);
queries!.cullingKeyResult.set(key, cullingKey);
return sourceID;
}

private createRenderQueue (sceneFlags: SceneFlags, subpassOrPassLayoutID: number): number {
const targetID = this.numRenderQueues++;
if (this.numRenderQueues > this.renderQueues.length) {
assert(this.numRenderQueues === (this.renderQueues.length + 1));
this.renderQueues.push(renderQueueRecycle.addWithArgs());
const renderQueue = this.cullingPools.renderQueueRecycle.add();
renderQueue.update();
this.renderQueues.push(renderQueue);
}
assert(targetID < this.renderQueues.length);
const rq = this.renderQueues[targetID];
Expand All @@ -362,8 +360,10 @@ export class SceneCulling {
const targetID = this.createRenderQueue(sceneData.flags, layoutID);

const lightType = sceneData.light.light ? sceneData.light.light.type : LightType.UNKNOWN;
const renderQueueDesc = this.cullingPools.renderQueueDescRecycle.add();
renderQueueDesc.update(sourceID, targetID, lightType);
// add render queue to query source
this.sceneQueryIndex.set(v, renderQueueDescRecycle.addWithArgs(sourceID, targetID, lightType));
this.sceneQueryIndex.set(v, renderQueueDesc);
}
}

Expand All @@ -389,7 +389,7 @@ export class SceneCulling {
assert(!!scene);
for (const [key, sourceID] of queries.culledResultIndex) {
const cullingKey = queries.cullingKeyResult.get(key)!;
const sceneData = cullingKey.sceneData;
const sceneData = cullingKey.sceneData!;
assert(!!sceneData.camera);
assert(sceneData.camera.scene === scene);
const camera = sceneData.camera;
Expand Down
24 changes: 8 additions & 16 deletions cocos/rendering/custom/web-pipeline-types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { RecyclePool, UpdateRecyclePool, cclegacy } from '../../core';
import { RecyclePool, cclegacy } from '../../core';
import { CommandBuffer, DescriptorSet, Device, PipelineState, RenderPass, deviceManager } from '../../gfx';
import { IMacroPatch } from '../../render-scene';
import { LightType, Model, SubModel } from '../../render-scene/scene';
Expand All @@ -7,7 +7,7 @@ import { InstancedBuffer } from '../instanced-buffer';
import { PipelineStateManager } from '../pipeline-state-manager';
import { SceneFlags } from './types';

export class DrawInstance extends UpdateRecyclePool {
export class DrawInstance {
subModel: SubModel | null;
priority: number;
hash: number;
Expand All @@ -23,7 +23,6 @@ export class DrawInstance extends UpdateRecyclePool {
shaderID = 0,
passIndex = 0,
) {
super();
this.subModel = subModel;
this.priority = priority;
this.hash = hash;
Expand All @@ -48,14 +47,7 @@ export class DrawInstance extends UpdateRecyclePool {
}
}

export const instancePool = new RecyclePool((
subModel: SubModel | null = null,
priority: number = 0,
hash: number = 0,
depth: number = 0,
shaderID: number = 0,
passIndex: number = 0,
) => new DrawInstance(subModel, priority, hash, depth, shaderID, passIndex), 0);
export const instancePool = new RecyclePool(() => new DrawInstance(), 8);

const CC_USE_RGBE_OUTPUT = 'CC_USE_RGBE_OUTPUT';
function getLayoutId (passLayout: string, phaseLayout: string): number {
Expand Down Expand Up @@ -135,8 +127,9 @@ export class RenderDrawQueue {
const shaderId = subModel.shaders[passIdx].typedID;
const hash = (0 << 30) | (passPriority as number << 16) | (modelPriority as number << 8) | passIdx;
const priority = model.priority;

this.instances.push(instancePool.addWithArgs(subModel, priority, hash, depth, shaderId, passIdx));
const instance = instancePool.add();
instance.update(subModel, priority, hash, depth, shaderId, passIdx);
this.instances.push(instance);
}
/**
* @en Comparison sorting function. Opaque objects are sorted by priority -> depth front to back -> shader ID.
Expand Down Expand Up @@ -265,7 +258,7 @@ export class RenderInstancingQueue {
}
}

export class RenderQueueDesc extends UpdateRecyclePool {
export class RenderQueueDesc {
culledSource: number;
renderQueueTarget: number;
lightType: LightType;
Expand All @@ -275,7 +268,6 @@ export class RenderQueueDesc extends UpdateRecyclePool {
renderQueueTargetIn = 0xFFFFFFFF,
lightTypeIn: LightType = LightType.UNKNOWN,
) {
super();
this.culledSource = culledSourceIn;
this.renderQueueTarget = renderQueueTargetIn;
this.lightType = lightTypeIn;
Expand All @@ -291,7 +283,7 @@ export class RenderQueueDesc extends UpdateRecyclePool {
}
}

export class RenderQueue extends UpdateRecyclePool {
export class RenderQueue {
probeQueue: ProbeHelperQueue = new ProbeHelperQueue();
opaqueQueue: RenderDrawQueue = new RenderDrawQueue();
transparentQueue: RenderDrawQueue = new RenderDrawQueue();
Expand Down
4 changes: 2 additions & 2 deletions cocos/rendering/custom/web-scene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,13 @@ export class WebSceneTask implements SceneTask {
}

public start (): void {
this._sceneCulling();
// do nothing
}
public join (): void {
// for web-pipeline, do nothing
}
public submit (): void {

// do nothing
}
get camera (): scene.Camera | null { return this._camera; }
get renderScene (): RenderScene | null {
Expand Down

0 comments on commit ed1652b

Please sign in to comment.