/
githubmirror
/
pixijs
Обзор
Документация
Войти
/
githubmirror
/
pixijs
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
src/scene/graphics/shared/GraphicsPipe.ts
243 строки
7 KB
Krzysztof Sternik
feat: Canvas renderer (#11815)
03 фев 2026, 18:43
Не верифицирован
03 фев 2026, 18:43
c52309f
Код
Авторство
О чём код?
import { ExtensionType } from '../../../extensions/Extensions'; import { State } from '../../../rendering/renderers/shared/state/State'; import { type Renderer } from '../../../rendering/renderers/types'; import { GCManagedHash } from '../../../utils/data/GCManagedHash'; import { BigPool } from '../../../utils/pool/PoolGroup'; import { type GPUData } from '../../view/ViewContainer'; import { color32BitToUniform } from '../gpu/colorToUniform'; import { BatchableGraphics } from './BatchableGraphics'; import type { InstructionSet } from '../../../rendering/renderers/shared/instructions/InstructionSet'; import type { RenderPipe } from '../../../rendering/renderers/shared/instructions/RenderPipe'; import type { Shader } from '../../../rendering/renderers/shared/shader/Shader'; import type { PoolItem } from '../../../utils/pool/Pool'; import type { Graphics } from './Graphics'; import type { GpuGraphicsContext, GraphicsContextSystem } from './GraphicsContextSystem'; /** @internal */ export interface GraphicsPipeLike { renderer: Renderer; state: State; } /** @internal */ export interface GraphicsAdaptor { shader: Shader; contextChange(renderer: Renderer): void; execute(graphicsPipe: GraphicsPipeLike, renderable: Graphics): void; destroy(): void; } /** @internal */ export class GraphicsGpuData implements GPUData { public batches: BatchableGraphics[] = []; public batched = false; public destroy() { this.batches.forEach((batch) => { BigPool.return(batch as PoolItem); }); this.batches.length = 0; } } /** @internal */ export class GraphicsPipe implements RenderPipe<Graphics> { /** @ignore */ public static extension = { type: [ ExtensionType.WebGLPipes, ExtensionType.WebGPUPipes, ], name: 'graphics', } as const; public renderer: Renderer; public state: State = State.for2d(); private _adaptor: GraphicsAdaptor; private readonly _managedGraphics: GCManagedHash<Graphics>; constructor(renderer: Renderer, adaptor: GraphicsAdaptor) { this.renderer = renderer; this._adaptor = adaptor; this.renderer.runners.contextChange.add(this); this._managedGraphics = new GCManagedHash({ renderer, type: 'renderable', priority: -1, name: 'graphics' }); } public contextChange(): void { this._adaptor.contextChange(this.renderer); } public validateRenderable(graphics: Graphics): boolean { // assume context is dirty.. const context = graphics.context; const wasBatched = !!graphics._gpuData; const contextSystem = this.renderer.graphicsContext as GraphicsContextSystem; const gpuContext = contextSystem.updateGpuContext(context); if (gpuContext.isBatchable || wasBatched !== gpuContext.isBatchable) { // TODO what if they are the same size?? return true; } return false; } public addRenderable(graphics: Graphics, instructionSet: InstructionSet) { const contextSystem = this.renderer.graphicsContext as GraphicsContextSystem; const gpuContext = contextSystem.updateGpuContext(graphics.context); // need to get batches here.. as we need to know if we can batch or not.. // this also overrides the current batches.. if (graphics.didViewUpdate) { this._rebuild(graphics); } if (gpuContext.isBatchable) { this._addToBatcher(graphics, instructionSet); } else { this.renderer.renderPipes.batch.break(instructionSet); instructionSet.add(graphics); } } public updateRenderable(graphics: Graphics) { const gpuData = this._getGpuDataForRenderable(graphics); const batches = gpuData.batches; for (let i = 0; i < batches.length; i++) { const batch = batches[i]; batch._batcher.updateElement(batch); } } public execute(graphics: Graphics) { if (!graphics.isRenderable) return; const renderer = this.renderer; const context = graphics.context; const contextSystem = renderer.graphicsContext as GraphicsContextSystem; // early out if there is no actual visual stuff... if (!contextSystem.getGpuContext(context).batches.length) { return; } const shader = context.customShader || this._adaptor.shader; this.state.blendMode = graphics.groupBlendMode; const localUniforms = shader.resources.localUniforms.uniforms; localUniforms.uTransformMatrix = graphics.groupTransform; localUniforms.uRound = renderer._roundPixels | graphics._roundPixels; color32BitToUniform( graphics.groupColorAlpha, localUniforms.uColor, 0, ); this._adaptor.execute(this, graphics); } private _rebuild(graphics: Graphics) { const gpuData = this._getGpuDataForRenderable(graphics); const contextSystem = this.renderer.graphicsContext as GraphicsContextSystem; const gpuContext = contextSystem.updateGpuContext(graphics.context); // free up the batches.. gpuData.destroy(); if (gpuContext.isBatchable) { this._updateBatchesForRenderable(graphics, gpuData); } } private _addToBatcher(graphics: Graphics, instructionSet: InstructionSet) { const batchPipe = this.renderer.renderPipes.batch; const batches = this._getGpuDataForRenderable(graphics).batches; for (let i = 0; i < batches.length; i++) { const batch = batches[i]; batchPipe.addToBatch(batch, instructionSet); } } private _getGpuDataForRenderable(graphics: Graphics): GraphicsGpuData { return graphics._gpuData[this.renderer.uid] || this._initGpuDataForRenderable(graphics); } private _initGpuDataForRenderable(graphics: Graphics): GraphicsGpuData { const gpuData = new GraphicsGpuData(); graphics._gpuData[this.renderer.uid] = gpuData; this._managedGraphics.add(graphics); return gpuData; } private _updateBatchesForRenderable(graphics: Graphics, gpuData: GraphicsGpuData) { const context = graphics.context; const contextSystem = this.renderer.graphicsContext as GraphicsContextSystem; const gpuContext: GpuGraphicsContext = contextSystem.getGpuContext(context); const roundPixels = (this.renderer._roundPixels | graphics._roundPixels) as 0 | 1; gpuData.batches = gpuContext.batches.map((batch) => { const batchClone = BigPool.get(BatchableGraphics); batch.copyTo(batchClone); batchClone.renderable = graphics; batchClone.roundPixels = roundPixels; return batchClone; }); } public destroy() { this._managedGraphics.destroy(); this.renderer = null; this._adaptor.destroy(); this._adaptor = null; this.state = null; } }