UNPKG

@lightningjs/renderer

Version:
198 lines (176 loc) 5.92 kB
/* * If not stated otherwise in this file or this component's LICENSE file the * following copyright and licenses apply: * * Copyright 2026 Comcast Cable Communications Management, LLC. * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { describe, expect, it, vi } from 'vitest'; import { CoreTextNode, type CoreTextNodeProps } from '../../CoreTextNode.js'; import type { Stage } from '../../Stage.js'; import type { TextRenderer } from '../../text-rendering/TextRenderer.js'; import { WebGlRenderer } from './WebGlRenderer.js'; import { WebGlShaderProgram } from './WebGlShaderProgram.js'; import { makeMockStage, makeTextProps as makeSharedTextProps, } from '../../../../test/mockStage.js'; const makeStage = (): Stage => makeMockStage({ pixelRatio: 2 }); const makeTextProps = (): CoreTextNodeProps => makeSharedTextProps({ h: 20, w: 100 }); const makeSdfTextRenderer = (): TextRenderer => ({ clearCache: vi.fn(), type: 'sdf', font: { isFontLoaded: vi.fn().mockReturnValue(true), loadFont: vi.fn(), waitingForFont: vi.fn(), stopWaitingForFont: vi.fn(), }, init: vi.fn(), renderText: vi.fn().mockReturnValue({ width: 100, height: 20, layout: { glyphs: [], width: 100, height: 20 }, }), addQuads: vi.fn().mockReturnValue(new Float32Array(0)), renderQuads: vi.fn(), } as unknown as TextRenderer); const makeSdfTextNode = () => { const node = new CoreTextNode( makeStage(), makeTextProps(), makeSdfTextRenderer(), ); node.parentHasRenderTexture = true; node.framebufferDimensions = { w: 320, h: 180 }; node.rttParent = { framebufferDimensions: { w: 640, h: 360 } } as any; return node; }; describe('WebGlShaderProgram.bindRenderOp', () => { function createProgram() { const program = Object.create( WebGlShaderProgram.prototype, ) as WebGlShaderProgram; const bindTextures = vi.fn(); const bindBufferCollection = vi.fn(); const uniform1f = vi.fn(); const uniform2f = vi.fn(); const glw = { canvas: { width: 1920, height: 1080 }, uniform1f, uniform2f, }; (program as any).bindTextures = bindTextures; (program as any).bindBufferCollection = bindBufferCollection; (program as any).glw = glw; (program as any).useTimeValue = false; (program as any).useSystemAlpha = false; (program as any).useSystemDimensions = false; return { program, bindTextures, bindBufferCollection, uniform1f, uniform2f, }; } it('binds an SdfRenderOp using the main framebuffer resolution', () => { const { program, bindTextures, bindBufferCollection, uniform1f, uniform2f, } = createProgram(); const renderOp = { isCoreNode: false, shader: { uniforms: { hasStoredUniforms: false } }, renderOpTextures: [], quadBufferCollection: {}, parentHasRenderTexture: false, framebufferDimensions: null, rtt: false, stage: { pixelRatio: 1.5 }, time: 0, worldAlpha: 1, w: 100, h: 20, }; program.bindRenderOp(renderOp as any); expect(bindTextures).toHaveBeenCalledWith(renderOp.renderOpTextures); expect(bindBufferCollection).toHaveBeenCalledWith( renderOp.quadBufferCollection, ); expect(uniform1f).toHaveBeenCalledWith('u_pixelRatio', 1.5); expect(uniform2f).toHaveBeenCalledWith('u_resolution', 1920, 1080); }); it('uses the parent framebuffer resolution for an SdfRenderOp in RTT', () => { const { program, uniform1f, uniform2f } = createProgram(); const renderOp = { isCoreNode: false, shader: { uniforms: { hasStoredUniforms: false } }, renderOpTextures: [], quadBufferCollection: {}, parentHasRenderTexture: true, framebufferDimensions: { w: 320, h: 180 }, rtt: false, stage: { pixelRatio: 2 }, time: 0, worldAlpha: 1, w: 100, h: 20, }; program.bindRenderOp(renderOp as any); expect(uniform1f).toHaveBeenCalledWith('u_pixelRatio', 1); expect(uniform2f).toHaveBeenCalledWith('u_resolution', 320, 180); }); it('uses parent RTT dimensions for core-node render ops', () => { const { program, uniform1f, uniform2f } = createProgram(); const renderOp = { framebufferDimensions: { w: 320, h: 180 }, isCoreNode: true, parentFramebufferDimensions: { w: 640, h: 360 }, parentHasRenderTexture: true, quadBufferCollection: {}, renderOpTextures: [], rtt: false, shader: { uniforms: { hasStoredUniforms: false }, }, stage: { pixelRatio: 2 }, time: 0, worldAlpha: 1, w: 100, h: 20, } as any; program.bindRenderOp(renderOp); expect(uniform1f).toHaveBeenCalledWith('u_pixelRatio', 1.0); expect(uniform2f).toHaveBeenCalledWith('u_resolution', 640, 360); }); }); describe('WebGlRenderer.canReuseRenderOp', () => { it('reuses SDF text render ops with matching parent RTT dimensions', () => { const renderer = Object.create(WebGlRenderer.prototype) as WebGlRenderer; renderer.stencilDepth = 0; const node = makeSdfTextNode(); node.stencilDepth = 0; node.props.shader = { shaderKey: 'default', } as any; renderer.curRenderOp = node; expect(renderer.reuseRenderOp(node)).toBe(true); }); });