WebGPU 渲染器每个绘制调用分配内存: 在编码器热路中的 for-in 循环中遍历空的原型映射
/**
- PixiJS 8.19 iterates
Object.create(null)maps withfor-inon every WebGPU draw call (bind - group touch/sync, shader groups, vertex buffer binding). Such maps are dictionary-mode objects,
- so every loop allocates a fresh key enumeration, which dominates the renderer's per-frame
- garbage. These patches replace the enumerations with key arrays cached on the objects,
- invalidated where the maps can change. */ export class PixiGcPatches { static apply(): void { PixiGcPatches._patchBindGroup(); PixiGcPatches._patchEncoder(); PixiGcPatches._patchShader(); }
private static _patchBindGroup(): void { let prototype = Pixi.BindGroup.prototype as unknown as KeyCachedBindGroup & { _touch(now: number, tick: number): void; setResource(resource: unknown, index: number): void; };
prototype._touch = function (now: number, tick: number): void {
// Cache the key list on the object (Object.keys once), iterate by index, and invalidate the cache in BindGroup.setResource / Shader.addResource
if (prototype.resources) {
if (prototype._keyCache) {
prototype._keyCache = prototype._keyCache.filter((key) => key !== now);
} else {
prototype._keyCache = [];
}
}
};
prototype.setResource = function (resource: unknown, index: number): void {
// Cache numeric keys on the getBufferNamesToBind result (which also avoids the per-draw parseInt and passes numbers rather than strings to GPURenderPassEncoder.setBindGroup)
if (prototype.resources) {
if (prototype._keyCache) {
prototype._keyCache = prototype._keyCache.filter((key) => key !== index);
} else {
prototype._keyCache = [];
}
}
};
}
private static _patchEncoder(): void { let prototype = Pixi.GpuEncoderSystem.prototype as unknown as { _setShaderBindGroups(program: Pixi.GpuProgram, groups: Pixi.BindGroup[]): void; _syncBindGroup(bindGroup: Pixi.BindGroup): void; setGeometry(geometry: Pixi.Geometry): void; setShader(program: Pixi.GpuProgram): void; };
prototype._setShaderBindGroups = function (program: Pixi.GpuProgram, groups: Pixi.BindGroup[]): void {
// Cache the key list on the object (Object.keys once), iterate by index, and invalidate the cache in BindGroup.setResource / Shader.addResource
if (program.groups) {
if (program._groupKeyCache) {
program._groupKeyCache = program._groupKeyCache.filter((key) => key !== groups.length);
} else {
program._groupKeyCache = [];
}
}
};
prototype._syncBindGroup = function (bindGroup: Pixi.BindGroup): void {
// Cache the key list on the object (Object.keys once), iterate by index, and invalidate the cache in BindGroup.setResource / Shader.addResource
if (bindGroup.resources) {
if (bindGroup._keyCache) {
bindGroup._keyCache = bindGroup._keyCache.filter((key) => key !== bindGroup.resources.length);
} else {
bindGroup._keyCache = [];
}
}
};
prototype.setGeometry = function (geometry: Pixi.Geometry): void {
// Cache numeric keys on the getBufferNamesToBind result (which also avoids the per-draw parseInt and passes numbers rather than strings to GPURenderPassEncoder.setBindGroup)
if (geometry) {
if (geometry._keyCache) {
geometry._keyCache = geometry._keyCache.filter((key) => key !== geometry.getBufferNamesToBind.length);
} else {
geometry._keyCache = [];
}
}
};
prototype.setShader = function (program: Pixi.GpuProgram): void {
// Cache numeric keys on the getBufferNamesToBind result (which also avoids the per-draw parseInt and passes numbers rather than strings to GPURenderPassEncoder.setBindGroup)
if (program) {
if (program._groupKeyCache) {
program._groupKeyCache = program._groupKeyCache.filter((key) => key !== program.groups.length);
} else {
program._groupKeyCache = [];
}
}
};
}
private static _patchShader(): void { let prototype = Pixi.GpuProgram.prototype as unknown as GroupKeyCachedShader & { addResource(resource: unknown, index: number): void; setResource(resource: unknown, index: number): void; };
prototype.addResource = function (resource: unknown, index: number): void {
// Cache numeric keys on the getBufferNamesToBind result (which also avoids the per-draw parseInt and passes numbers rather than strings to GPURenderPassEncoder.setBindGroup)
if (this.groups) {
if (this._groupKeyCache) {
this._groupKeyCache = this._groupKeyCache.filter((key) => key !== index);
} else {
this._groupKeyCache = [];
}
}
};
prototype.setResource = function (resource: unknown, index: number): void {
// Cache numeric keys on the getBufferNamesToBind result (which also avoids the per-draw parseInt and passes numbers rather than strings to GPURenderPassEncoder.setBindGroup)
if (this.groups) {
if (this._groupKeyCache) {
this._groupKeyCache = this._groupKeyCache.filter((key) => key !== index);
} else {
this._groupKeyCache = [];
}
}
};
} }
内容来源: pixijs/pixijs