/
githubmirror
/
pixijs
Обзор
Документация
Войти
/
githubmirror
/
pixijs
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
src/rendering/renderers/gpu/BindGroupSystem.ts
159 строк
6 KB
Zyie
fix: prevent double-destroy of render targets on teardown (#12095)
08 июл 2026, 13:23
Не верифицирован
08 июл 2026, 13:23
767b016
Код
Авторство
О чём код?
import { ExtensionType } from '../../../extensions/Extensions'; import type { Buffer } from '../shared/buffer/Buffer'; import type { BufferResource } from '../shared/buffer/BufferResource'; import type { UniformGroup } from '../shared/shader/UniformGroup'; import type { System } from '../shared/system/System'; import type { TextureSource } from '../shared/texture/sources/TextureSource'; import type { TextureStyle } from '../shared/texture/TextureStyle'; import type { TextureView } from '../shared/texture/TextureView'; import type { GPU } from './GpuDeviceSystem'; import type { BindGroup } from './shader/BindGroup'; import type { BindResource } from './shader/BindResource'; import type { GpuProgram } from './shader/GpuProgram'; import type { WebGPURenderer } from './WebGPURenderer'; /** * This manages the WebGPU bind groups. this is how data is bound to a shader when rendering * @category rendering * @advanced */ export class BindGroupSystem implements System { /** @ignore */ public static extension = { type: [ ExtensionType.WebGPUSystem, ], name: 'bindGroup', } as const; private readonly _renderer: WebGPURenderer; private _hash: Record<string, GPUBindGroup> = Object.create(null); private _gpu: GPU; constructor(renderer: WebGPURenderer) { this._renderer = renderer; } protected contextChange(gpu: GPU): void { this._gpu = gpu; } public getBindGroup(bindGroup: BindGroup, program: GpuProgram, groupIndex: number): GPUBindGroup { // The cache key must include both the resources AND the program layout, // because a GPUBindGroup must exactly match its GPUBindGroupLayout. // Two programs with different layouts cannot share a GPUBindGroup, // even if they use the same resources. // Bit shift combines layoutKey and groupIndex into single number (groupIndex < 16) const key = `${bindGroup._key}:${(program._layoutKey << 4) | groupIndex}`; const gpuBindGroup = this._hash[key] || this._createBindGroup(key, bindGroup, program, groupIndex); return gpuBindGroup; } private _createBindGroup(key: string, group: BindGroup, program: GpuProgram, groupIndex: number): GPUBindGroup { const device = this._gpu.device; const groupLayout = program.layout[groupIndex]; const entries: GPUBindGroupEntry[] = []; const renderer = this._renderer; for (const j in groupLayout) { // resources may be keyed by resource name or by binding index — try the name first const resource: BindResource = group.resources[j] ?? group.resources[groupLayout[j]]; // a destroyed resource leaves a null slot (see BindGroup.onResourceChange) or may // have been handed in already destroyed — either way this group cannot render if (!resource || resource.destroyed) { throw new Error(`[BindGroup] the resource bound as '${j}' was destroyed while a shader still uses it. ` + 'Remove it from the shader before destroying it.'); } let gpuResource: GPUSampler | GPUTextureView | GPUExternalTexture | GPUBufferBinding; // TODO make this dynamic.. if (resource._resourceType === 'uniformGroup') { const uniformGroup = resource as UniformGroup; renderer.ubo.updateUniformGroup(uniformGroup as UniformGroup); const buffer = uniformGroup.buffer; gpuResource = { buffer: renderer.buffer.getGPUBuffer(buffer), offset: 0, size: buffer.descriptor.size, }; } else if (resource._resourceType === 'buffer') { const buffer = resource as Buffer; gpuResource = { buffer: renderer.buffer.getGPUBuffer(buffer), offset: 0, size: buffer.descriptor.size, }; } else if (resource._resourceType === 'bufferResource') { const bufferResource = resource as BufferResource; gpuResource = { buffer: renderer.buffer.getGPUBuffer(bufferResource.buffer), offset: bufferResource.offset, size: bufferResource.size ?? bufferResource.buffer.descriptor.size, }; } else if (resource._resourceType === 'textureSampler') { const sampler = resource as TextureStyle; gpuResource = renderer.texture.getGpuSampler(sampler); } else if (resource._resourceType === 'textureSource') { const texture = resource as TextureSource; gpuResource = renderer.texture.getTextureView(texture); } else if (resource._resourceType === 'textureView') { const textureView = resource as TextureView; gpuResource = renderer.texture.getTextureView(textureView.source, textureView.viewDescriptor); } entries.push({ binding: groupLayout[j], resource: gpuResource, }); } const layout = renderer.shader.getProgramData(program).bindGroups[groupIndex]; const gpuBindGroup = device.createBindGroup({ layout, entries, }); this._hash[key] = gpuBindGroup; return gpuBindGroup; } public destroy(): void { this._hash = null; (this._renderer as null) = null; } }