UNPKG

34.1 kBSource Map (JSON)View Raw
1{"version":3,"file":"BatchRenderer.js","sources":["../../src/batch/BatchRenderer.ts"],"sourcesContent":["import { Color } from '@pixi/color';\nimport { ENV } from '@pixi/constants';\nimport { extensions, ExtensionType } from '@pixi/extensions';\nimport { settings } from '@pixi/settings';\nimport { deprecation, log2, nextPow2, premultiplyBlendMode } from '@pixi/utils';\nimport { ViewableBuffer } from '../geometry/ViewableBuffer';\nimport { checkMaxIfStatementsInShader } from '../shader/utils/checkMaxIfStatementsInShader';\nimport { State } from '../state/State';\nimport { BaseTexture } from '../textures/BaseTexture';\nimport { BatchDrawCall } from './BatchDrawCall';\nimport { BatchGeometry } from './BatchGeometry';\nimport { BatchShaderGenerator } from './BatchShaderGenerator';\nimport { BatchTextureArray } from './BatchTextureArray';\nimport { canUploadSameBuffer } from './canUploadSameBuffer';\nimport { maxRecommendedTextures } from './maxRecommendedTextures';\nimport { ObjectRenderer } from './ObjectRenderer';\nimport defaultFragment from './texture.frag';\nimport defaultVertex from './texture.vert';\n\nimport type { BLEND_MODES } from '@pixi/constants';\nimport type { ExtensionMetadata } from '@pixi/extensions';\nimport type { Renderer } from '../Renderer';\nimport type { Shader } from '../shader/Shader';\nimport type { Texture } from '../textures/Texture';\n\n/**\n * Interface for elements like Sprite, Mesh etc. for batching.\n * @memberof PIXI\n */\nexport interface IBatchableElement\n{\n _texture: Texture;\n vertexData: Float32Array;\n indices: Uint16Array | Uint32Array | Array<number>;\n uvs: Float32Array;\n worldAlpha: number;\n _tintRGB: number;\n blendMode: BLEND_MODES;\n}\n\n/**\n * Renderer dedicated to drawing and batching sprites.\n *\n * This is the default batch renderer. It buffers objects\n * with texture-based geometries and renders them in\n * batches. It uploads multiple textures to the GPU to\n * reduce to the number of draw calls.\n * @memberof PIXI\n */\nexport class BatchRenderer extends ObjectRenderer\n{\n /**\n * The maximum textures that this device supports.\n * @static\n * @default 32\n */\n public static get defaultMaxTextures(): number\n {\n this._defaultMaxTextures = this._defaultMaxTextures ?? maxRecommendedTextures(32);\n\n return this._defaultMaxTextures;\n }\n public static set defaultMaxTextures(value: number)\n {\n this._defaultMaxTextures = value;\n }\n\n /** @ignore */\n private static _defaultMaxTextures: number;\n\n /**\n * The default sprite batch size.\n *\n * The default aims to balance desktop and mobile devices.\n * @static\n */\n public static defaultBatchSize = 4096;\n\n /**\n * Can we upload the same buffer in a single frame?\n * @static\n */\n public static get canUploadSameBuffer(): boolean\n {\n this._canUploadSameBuffer = this._canUploadSameBuffer ?? canUploadSameBuffer();\n\n return this._canUploadSameBuffer;\n }\n public static set canUploadSameBuffer(value: boolean)\n {\n this._canUploadSameBuffer = value;\n }\n\n /** @ignore */\n private static _canUploadSameBuffer: boolean;\n\n /** @ignore */\n static extension: ExtensionMetadata = {\n name: 'batch',\n type: ExtensionType.RendererPlugin,\n };\n\n /** The WebGL state in which this renderer will work. */\n public readonly state: State;\n\n /**\n * The number of bufferable objects before a flush\n * occurs automatically.\n * @default PIXI.BatchRenderer.defaultBatchSize * 4\n */\n public size: number;\n\n /**\n * Maximum number of textures that can be uploaded to\n * the GPU under the current context. It is initialized\n * properly in `this.contextChange`.\n * @see PIXI.BatchRenderer#contextChange\n * @readonly\n */\n public maxTextures: number;\n\n /**\n * This is used to generate a shader that can\n * color each vertex based on a `aTextureId`\n * attribute that points to an texture in `uSampler`.\n *\n * This enables the objects with different textures\n * to be drawn in the same draw call.\n *\n * You can customize your shader by creating your\n * custom shader generator.\n */\n protected shaderGenerator: BatchShaderGenerator;\n\n /**\n * The class that represents the geometry of objects\n * that are going to be batched with this.\n * @member {object}\n * @default PIXI.BatchGeometry\n */\n protected geometryClass: typeof BatchGeometry;\n\n /**\n * Size of data being buffered per vertex in the\n * attribute buffers (in floats). By default, the\n * batch-renderer plugin uses 6:\n *\n * | aVertexPosition | 2 |\n * |-----------------|---|\n * | aTextureCoords | 2 |\n * | aColor | 1 |\n * | aTextureId | 1 |\n * @default 6\n */\n protected vertexSize: number;\n\n /** Total count of all vertices used by the currently buffered objects. */\n protected _vertexCount: number;\n\n /** Total count of all indices used by the currently buffered objects. */\n protected _indexCount: number;\n\n /**\n * Buffer of objects that are yet to be rendered.\n * @member {PIXI.DisplayObject[]}\n */\n protected _bufferedElements: Array<IBatchableElement>;\n\n /**\n * Data for texture batch builder, helps to save a bit of CPU on a pass.\n * @member {PIXI.BaseTexture[]}\n */\n protected _bufferedTextures: Array<BaseTexture>;\n\n /** Number of elements that are buffered and are waiting to be flushed. */\n protected _bufferSize: number;\n\n /**\n * This shader is generated by `this.shaderGenerator`.\n *\n * It is generated specifically to handle the required\n * number of textures being batched together.\n */\n protected _shader: Shader;\n\n /**\n * A flush may occur multiple times in a single\n * frame. On iOS devices or when\n * `BatchRenderer.canUploadSameBuffer` is false, the\n * batch renderer does not upload data to the same\n * `WebGLBuffer` for performance reasons.\n *\n * This is the index into `packedGeometries` that points to\n * geometry holding the most recent buffers.\n */\n protected _flushId: number;\n\n /**\n * Pool of `ViewableBuffer` objects that are sorted in\n * order of increasing size. The flush method uses\n * the buffer with the least size above the amount\n * it requires. These are used for passing attributes.\n *\n * The first buffer has a size of 8; each subsequent\n * buffer has double capacity of its previous.\n * @member {PIXI.ViewableBuffer[]}\n * @see PIXI.BatchRenderer#getAttributeBuffer\n */\n protected _aBuffers: Array<ViewableBuffer>;\n\n /**\n * Pool of `Uint16Array` objects that are sorted in\n * order of increasing size. The flush method uses\n * the buffer with the least size above the amount\n * it requires. These are used for passing indices.\n *\n * The first buffer has a size of 12; each subsequent\n * buffer has double capacity of its previous.\n * @member {Uint16Array[]}\n * @see PIXI.BatchRenderer#getIndexBuffer\n */\n protected _iBuffers: Array<Uint16Array>;\n protected _dcIndex: number;\n protected _aIndex: number;\n protected _iIndex: number;\n protected _attributeBuffer: ViewableBuffer;\n protected _indexBuffer: Uint16Array;\n protected _tempBoundTextures: BaseTexture[];\n\n /**\n * Pool of `this.geometryClass` geometry objects\n * that store buffers. They are used to pass data\n * to the shader on each draw call.\n *\n * These are never re-allocated again, unless a\n * context change occurs; however, the pool may\n * be expanded if required.\n * @member {PIXI.Geometry[]}\n * @see PIXI.BatchRenderer.contextChange\n */\n private _packedGeometries: Array<BatchGeometry>;\n\n /**\n * Size of `this._packedGeometries`. It can be expanded\n * if more than `this._packedGeometryPoolSize` flushes\n * occur in a single frame.\n */\n private _packedGeometryPoolSize: number;\n\n /**\n * This will hook onto the renderer's `contextChange`\n * and `prerender` signals.\n * @param {PIXI.Renderer} renderer - The renderer this works for.\n */\n constructor(renderer: Renderer)\n {\n super(renderer);\n\n this.setShaderGenerator();\n this.geometryClass = BatchGeometry;\n this.vertexSize = 6;\n this.state = State.for2d();\n this.size = BatchRenderer.defaultBatchSize * 4;\n this._vertexCount = 0;\n this._indexCount = 0;\n this._bufferedElements = [];\n this._bufferedTextures = [];\n this._bufferSize = 0;\n this._shader = null;\n this._packedGeometries = [];\n this._packedGeometryPoolSize = 2;\n this._flushId = 0;\n this._aBuffers = {} as any;\n this._iBuffers = {} as any;\n\n this.maxTextures = 1;\n\n this.renderer.on('prerender', this.onPrerender, this);\n renderer.runners.contextChange.add(this);\n\n this._dcIndex = 0;\n this._aIndex = 0;\n this._iIndex = 0;\n this._attributeBuffer = null;\n this._indexBuffer = null;\n this._tempBoundTextures = [];\n }\n\n /**\n * @see PIXI.BatchRenderer#maxTextures\n * @deprecated since 7.1.0\n * @readonly\n */\n get MAX_TEXTURES(): number\n {\n if (process.env.DEBUG)\n {\n deprecation('7.1.0', 'BatchRenderer#MAX_TEXTURES renamed to BatchRenderer#maxTextures');\n }\n\n return this.maxTextures;\n }\n\n /**\n * The default vertex shader source\n * @readonly\n */\n static get defaultVertexSrc(): string\n {\n return defaultVertex;\n }\n\n /**\n * The default fragment shader source\n * @readonly\n */\n static get defaultFragmentTemplate(): string\n {\n return defaultFragment;\n }\n\n /**\n * Set the shader generator.\n * @param {object} [options]\n * @param {string} [options.vertex=PIXI.BatchRenderer.defaultVertexSrc] - Vertex shader source\n * @param {string} [options.fragment=PIXI.BatchRenderer.defaultFragmentTemplate] - Fragment shader template\n */\n public setShaderGenerator({\n vertex = BatchRenderer.defaultVertexSrc,\n fragment = BatchRenderer.defaultFragmentTemplate\n }: { vertex?: string, fragment?: string } = {}): void\n {\n this.shaderGenerator = new BatchShaderGenerator(vertex, fragment);\n }\n\n /**\n * Handles the `contextChange` signal.\n *\n * It calculates `this.maxTextures` and allocating the packed-geometry object pool.\n */\n contextChange(): void\n {\n const gl = this.renderer.gl;\n\n if (settings.PREFER_ENV === ENV.WEBGL_LEGACY)\n {\n this.maxTextures = 1;\n }\n else\n {\n // step 1: first check max textures the GPU can handle.\n this.maxTextures = Math.min(\n gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS),\n BatchRenderer.defaultMaxTextures);\n\n // step 2: check the maximum number of if statements the shader can have too..\n this.maxTextures = checkMaxIfStatementsInShader(\n this.maxTextures, gl);\n }\n\n this._shader = this.shaderGenerator.generateShader(this.maxTextures);\n\n // we use the second shader as the first one depending on your browser\n // may omit aTextureId as it is not used by the shader so is optimized out.\n for (let i = 0; i < this._packedGeometryPoolSize; i++)\n {\n /* eslint-disable max-len */\n this._packedGeometries[i] = new (this.geometryClass)();\n }\n\n this.initFlushBuffers();\n }\n\n /** Makes sure that static and dynamic flush pooled objects have correct dimensions. */\n initFlushBuffers(): void\n {\n const {\n _drawCallPool,\n _textureArrayPool,\n } = BatchRenderer;\n // max draw calls\n const MAX_SPRITES = this.size / 4;\n // max texture arrays\n const MAX_TA = Math.floor(MAX_SPRITES / this.maxTextures) + 1;\n\n while (_drawCallPool.length < MAX_SPRITES)\n {\n _drawCallPool.push(new BatchDrawCall());\n }\n while (_textureArrayPool.length < MAX_TA)\n {\n _textureArrayPool.push(new BatchTextureArray());\n }\n for (let i = 0; i < this.maxTextures; i++)\n {\n this._tempBoundTextures[i] = null;\n }\n }\n\n /** Handles the `prerender` signal. It ensures that flushes start from the first geometry object again. */\n onPrerender(): void\n {\n this._flushId = 0;\n }\n\n /**\n * Buffers the \"batchable\" object. It need not be rendered immediately.\n * @param {PIXI.DisplayObject} element - the element to render when\n * using this renderer\n */\n render(element: IBatchableElement): void\n {\n if (!element._texture.valid)\n {\n return;\n }\n\n if (this._vertexCount + (element.vertexData.length / 2) > this.size)\n {\n this.flush();\n }\n\n this._vertexCount += element.vertexData.length / 2;\n this._indexCount += element.indices.length;\n this._bufferedTextures[this._bufferSize] = element._texture.baseTexture;\n this._bufferedElements[this._bufferSize++] = element;\n }\n\n buildTexturesAndDrawCalls(): void\n {\n const {\n _bufferedTextures: textures,\n maxTextures,\n } = this;\n const textureArrays = BatchRenderer._textureArrayPool;\n const batch = this.renderer.batch;\n const boundTextures = this._tempBoundTextures;\n const touch = this.renderer.textureGC.count;\n\n let TICK = ++BaseTexture._globalBatch;\n let countTexArrays = 0;\n let texArray = textureArrays[0];\n let start = 0;\n\n batch.copyBoundTextures(boundTextures, maxTextures);\n\n for (let i = 0; i < this._bufferSize; ++i)\n {\n const tex = textures[i];\n\n textures[i] = null;\n if (tex._batchEnabled === TICK)\n {\n continue;\n }\n\n if (texArray.count >= maxTextures)\n {\n batch.boundArray(texArray, boundTextures, TICK, maxTextures);\n this.buildDrawCalls(texArray, start, i);\n start = i;\n texArray = textureArrays[++countTexArrays];\n ++TICK;\n }\n\n tex._batchEnabled = TICK;\n tex.touched = touch;\n texArray.elements[texArray.count++] = tex;\n }\n\n if (texArray.count > 0)\n {\n batch.boundArray(texArray, boundTextures, TICK, maxTextures);\n this.buildDrawCalls(texArray, start, this._bufferSize);\n ++countTexArrays;\n ++TICK;\n }\n\n // Clean-up\n\n for (let i = 0; i < boundTextures.length; i++)\n {\n boundTextures[i] = null;\n }\n BaseTexture._globalBatch = TICK;\n }\n\n /**\n * Populating drawcalls for rendering\n * @param texArray\n * @param start\n * @param finish\n */\n buildDrawCalls(texArray: BatchTextureArray, start: number, finish: number): void\n {\n const {\n _bufferedElements: elements,\n _attributeBuffer,\n _indexBuffer,\n vertexSize,\n } = this;\n const drawCalls = BatchRenderer._drawCallPool;\n\n let dcIndex = this._dcIndex;\n let aIndex = this._aIndex;\n let iIndex = this._iIndex;\n\n let drawCall = drawCalls[dcIndex];\n\n drawCall.start = this._iIndex;\n drawCall.texArray = texArray;\n\n for (let i = start; i < finish; ++i)\n {\n const sprite = elements[i];\n const tex = sprite._texture.baseTexture;\n const spriteBlendMode = premultiplyBlendMode[\n tex.alphaMode ? 1 : 0][sprite.blendMode];\n\n elements[i] = null;\n\n if (start < i && drawCall.blend !== spriteBlendMode)\n {\n drawCall.size = iIndex - drawCall.start;\n start = i;\n drawCall = drawCalls[++dcIndex];\n drawCall.texArray = texArray;\n drawCall.start = iIndex;\n }\n\n this.packInterleavedGeometry(sprite, _attributeBuffer, _indexBuffer, aIndex, iIndex);\n aIndex += sprite.vertexData.length / 2 * vertexSize;\n iIndex += sprite.indices.length;\n\n drawCall.blend = spriteBlendMode;\n }\n\n if (start < finish)\n {\n drawCall.size = iIndex - drawCall.start;\n ++dcIndex;\n }\n\n this._dcIndex = dcIndex;\n this._aIndex = aIndex;\n this._iIndex = iIndex;\n }\n\n /**\n * Bind textures for current rendering\n * @param texArray\n */\n bindAndClearTexArray(texArray: BatchTextureArray): void\n {\n const textureSystem = this.renderer.texture;\n\n for (let j = 0; j < texArray.count; j++)\n {\n textureSystem.bind(texArray.elements[j], texArray.ids[j]);\n texArray.elements[j] = null;\n }\n texArray.count = 0;\n }\n\n updateGeometry(): void\n {\n const {\n _packedGeometries: packedGeometries,\n _attributeBuffer: attributeBuffer,\n _indexBuffer: indexBuffer,\n } = this;\n\n if (!BatchRenderer.canUploadSameBuffer)\n { /* Usually on iOS devices, where the browser doesn't\n like uploads to the same buffer in a single frame. */\n if (this._packedGeometryPoolSize <= this._flushId)\n {\n this._packedGeometryPoolSize++;\n packedGeometries[this._flushId] = new (this.geometryClass)();\n }\n\n packedGeometries[this._flushId]._buffer.update(attributeBuffer.rawBinaryData);\n packedGeometries[this._flushId]._indexBuffer.update(indexBuffer);\n\n this.renderer.geometry.bind(packedGeometries[this._flushId]);\n this.renderer.geometry.updateBuffers();\n this._flushId++;\n }\n else\n {\n // lets use the faster option, always use buffer number 0\n packedGeometries[this._flushId]._buffer.update(attributeBuffer.rawBinaryData);\n packedGeometries[this._flushId]._indexBuffer.update(indexBuffer);\n\n this.renderer.geometry.updateBuffers();\n }\n }\n\n drawBatches(): void\n {\n const dcCount = this._dcIndex;\n const { gl, state: stateSystem } = this.renderer;\n const drawCalls = BatchRenderer._drawCallPool;\n\n let curTexArray = null;\n\n // Upload textures and do the draw calls\n for (let i = 0; i < dcCount; i++)\n {\n const { texArray, type, size, start, blend } = drawCalls[i];\n\n if (curTexArray !== texArray)\n {\n curTexArray = texArray;\n this.bindAndClearTexArray(texArray);\n }\n\n this.state.blendMode = blend;\n stateSystem.set(this.state);\n gl.drawElements(type, size, gl.UNSIGNED_SHORT, start * 2);\n }\n }\n\n /** Renders the content _now_ and empties the current batch. */\n flush(): void\n {\n if (this._vertexCount === 0)\n {\n return;\n }\n\n this._attributeBuffer = this.getAttributeBuffer(this._vertexCount);\n this._indexBuffer = this.getIndexBuffer(this._indexCount);\n this._aIndex = 0;\n this._iIndex = 0;\n this._dcIndex = 0;\n\n this.buildTexturesAndDrawCalls();\n this.updateGeometry();\n this.drawBatches();\n\n // reset elements buffer for the next flush\n this._bufferSize = 0;\n this._vertexCount = 0;\n this._indexCount = 0;\n }\n\n /** Starts a new sprite batch. */\n start(): void\n {\n this.renderer.state.set(this.state);\n\n this.renderer.texture.ensureSamplerType(this.maxTextures);\n\n this.renderer.shader.bind(this._shader);\n\n if (BatchRenderer.canUploadSameBuffer)\n {\n // bind buffer #0, we don't need others\n this.renderer.geometry.bind(this._packedGeometries[this._flushId]);\n }\n }\n\n /** Stops and flushes the current batch. */\n stop(): void\n {\n this.flush();\n }\n\n /** Destroys this `BatchRenderer`. It cannot be used again. */\n destroy(): void\n {\n for (let i = 0; i < this._packedGeometryPoolSize; i++)\n {\n if (this._packedGeometries[i])\n {\n this._packedGeometries[i].destroy();\n }\n }\n\n this.renderer.off('prerender', this.onPrerender, this);\n\n this._aBuffers = null;\n this._iBuffers = null;\n this._packedGeometries = null;\n this._attributeBuffer = null;\n this._indexBuffer = null;\n\n if (this._shader)\n {\n this._shader.destroy();\n this._shader = null;\n }\n\n super.destroy();\n }\n\n /**\n * Fetches an attribute buffer from `this._aBuffers` that can hold atleast `size` floats.\n * @param size - minimum capacity required\n * @returns - buffer than can hold atleast `size` floats\n */\n getAttributeBuffer(size: number): ViewableBuffer\n {\n // 8 vertices is enough for 2 quads\n const roundedP2 = nextPow2(Math.ceil(size / 8));\n const roundedSizeIndex = log2(roundedP2);\n const roundedSize = roundedP2 * 8;\n\n if (this._aBuffers.length <= roundedSizeIndex)\n {\n this._iBuffers.length = roundedSizeIndex + 1;\n }\n\n let buffer = this._aBuffers[roundedSize];\n\n if (!buffer)\n {\n this._aBuffers[roundedSize] = buffer = new ViewableBuffer(roundedSize * this.vertexSize * 4);\n }\n\n return buffer;\n }\n\n /**\n * Fetches an index buffer from `this._iBuffers` that can\n * have at least `size` capacity.\n * @param size - minimum required capacity\n * @returns - buffer that can fit `size` indices.\n */\n getIndexBuffer(size: number): Uint16Array\n {\n // 12 indices is enough for 2 quads\n const roundedP2 = nextPow2(Math.ceil(size / 12));\n const roundedSizeIndex = log2(roundedP2);\n const roundedSize = roundedP2 * 12;\n\n if (this._iBuffers.length <= roundedSizeIndex)\n {\n this._iBuffers.length = roundedSizeIndex + 1;\n }\n\n let buffer = this._iBuffers[roundedSizeIndex];\n\n if (!buffer)\n {\n this._iBuffers[roundedSizeIndex] = buffer = new Uint16Array(roundedSize);\n }\n\n return buffer;\n }\n\n /**\n * Takes the four batching parameters of `element`, interleaves\n * and pushes them into the batching attribute/index buffers given.\n *\n * It uses these properties: `vertexData` `uvs`, `textureId` and\n * `indicies`. It also uses the \"tint\" of the base-texture, if\n * present.\n * @param {PIXI.DisplayObject} element - element being rendered\n * @param attributeBuffer - attribute buffer.\n * @param indexBuffer - index buffer\n * @param aIndex - number of floats already in the attribute buffer\n * @param iIndex - number of indices already in `indexBuffer`\n */\n packInterleavedGeometry(element: IBatchableElement, attributeBuffer: ViewableBuffer, indexBuffer: Uint16Array,\n aIndex: number, iIndex: number): void\n {\n const {\n uint32View,\n float32View,\n } = attributeBuffer;\n\n const packedVertices = aIndex / this.vertexSize;\n const uvs = element.uvs;\n const indicies = element.indices;\n const vertexData = element.vertexData;\n const textureId = element._texture.baseTexture._batchLocation;\n\n const alpha = Math.min(element.worldAlpha, 1.0);\n const argb = Color.shared\n .setValue(element._tintRGB)\n .toPremultiplied(alpha, element._texture.baseTexture.alphaMode > 0);\n\n // lets not worry about tint! for now..\n for (let i = 0; i < vertexData.length; i += 2)\n {\n float32View[aIndex++] = vertexData[i];\n float32View[aIndex++] = vertexData[i + 1];\n float32View[aIndex++] = uvs[i];\n float32View[aIndex++] = uvs[i + 1];\n uint32View[aIndex++] = argb;\n float32View[aIndex++] = textureId;\n }\n\n for (let i = 0; i < indicies.length; i++)\n {\n indexBuffer[iIndex++] = packedVertices + indicies[i];\n }\n }\n\n /**\n * Pool of `BatchDrawCall` objects that `flush` used\n * to create \"batches\" of the objects being rendered.\n *\n * These are never re-allocated again.\n * Shared between all batch renderers because it can be only one \"flush\" working at the moment.\n * @member {PIXI.BatchDrawCall[]}\n */\n static _drawCallPool: Array<BatchDrawCall> = [];\n\n /**\n * Pool of `BatchDrawCall` objects that `flush` used\n * to create \"batches\" of the objects being rendered.\n *\n * These are never re-allocated again.\n * Shared between all batch renderers because it can be only one \"flush\" working at the moment.\n * @member {PIXI.BatchTextureArray[]}\n */\n static _textureArrayPool: Array<BatchTextureArray> = [];\n}\n\n// Install BatchRenderer as default\nextensions.add(BatchRenderer);\n"],"names":["_BatchRenderer","ObjectRenderer","BatchGeometry","State","maxRecommendedTextures","canUploadSameBuffer","deprecation","defaultVertex","defaultFragment","BatchShaderGenerator","settings","ENV","checkMaxIfStatementsInShader","BatchDrawCall","BatchTextureArray","BaseTexture","premultiplyBlendMode","nextPow2","log2","ViewableBuffer","Color","ExtensionType","extensions"],"mappings":"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"}
\No newline at end of file