diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c104c3d23156e..89616bbd870762 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: contents: read steps: - name: Git checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - name: Install Node uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: @@ -54,7 +54,7 @@ jobs: CI: ${{ matrix.CI }} steps: - name: Git checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - name: Install Node uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: diff --git a/.github/workflows/codeql-code-scanning.yml b/.github/workflows/codeql-code-scanning.yml index f9ba5948c52fa5..9614b9c71d0882 100644 --- a/.github/workflows/codeql-code-scanning.yml +++ b/.github/workflows/codeql-code-scanning.yml @@ -29,20 +29,20 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4 + uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4 with: languages: ${{ matrix.language }} config-file: ./.github/codeql-config.yml queries: security-and-quality - name: Autobuild - uses: github/codeql-action/autobuild@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4 + uses: github/codeql-action/autobuild@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4 + uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/read-size.yml b/.github/workflows/read-size.yml index 2686e8898209c6..807026a7b25fa1 100644 --- a/.github/workflows/read-size.yml +++ b/.github/workflows/read-size.yml @@ -22,7 +22,7 @@ jobs: contents: read steps: - name: Git checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - name: Install Node uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: diff --git a/.github/workflows/report-size.yml b/.github/workflows/report-size.yml index d206b5ba3eca1a..ad38c3f904ba0e 100644 --- a/.github/workflows/report-size.yml +++ b/.github/workflows/report-size.yml @@ -58,7 +58,7 @@ jobs: # This runs on the base branch of the PR, meaning "dev" - name: Git checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - name: Install Node uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: diff --git a/examples/webgpu_compute_nanite-style.html b/examples/webgpu_compute_nanite-style.html index bb381c87f7a6bf..f73da227c66fa4 100644 --- a/examples/webgpu_compute_nanite-style.html +++ b/examples/webgpu_compute_nanite-style.html @@ -302,7 +302,7 @@ parameterGroup.add( options, 'Rasterizer', { 'SW Only': 'SW Only', 'HW Only': 'HW Only', 'Both': 'Both' } ); - parameterGroup.add( timeScale, 'value', 0.0, 1.0 ); + parameterGroup.add( timeScale, 'value', 0.0, 1.0 ).name( 'Animation Speed' ); // Atomic visibility buffers — pack depth + payload into single u32 for race-free atomicMax // Buffer A: depth(18 high bits) | megaTriangleIndex(14 low bits) — triangle ID diff --git a/src/renderers/common/Lighting.js b/src/renderers/common/Lighting.js index f2b6b9f2f654bd..94c5e259ce30be 100644 --- a/src/renderers/common/Lighting.js +++ b/src/renderers/common/Lighting.js @@ -27,6 +27,14 @@ class Lighting { */ this.enabled = true; + /** + * A stack of light arrays saved per render via {@link Lighting#beginRender}. + * + * @private + * @type {Array>} + */ + this._cache = []; + } /** @@ -42,10 +50,9 @@ class Lighting { } /** - * Returns a lights node for the given scene and camera. + * Returns a lights node for the given scene. * * @param {Scene} scene - The scene. - * @param {Camera} camera - The camera. * @return {LightsNode} The lights node. */ getNode( scene ) { @@ -66,6 +73,33 @@ class Lighting { } + /** + * Saves the current lights of the scene's lights node so they can be restored + * in {@link Lighting#finishRender}. Must be paired with a `finishRender()` call + * to avoid memory leaks. + * + * Nested render calls might mutate the lights array so a save/restore is required + * for each render call. + * + * @param {Scene} scene - The scene. + */ + beginRender( scene ) { + + this._cache.push( this.getNode( scene ).getLights() ); + + } + + /** + * Restores the lights saved by the matching {@link Lighting#beginRender} call. + * + * @param {Scene} scene - The scene. + */ + finishRender( scene ) { + + this.getNode( scene ).setLights( this._cache.pop() ); + + } + } export default Lighting; diff --git a/src/renderers/common/Renderer.js b/src/renderers/common/Renderer.js index a03b1bb93ed7e6..20452771dd8cc6 100644 --- a/src/renderers/common/Renderer.js +++ b/src/renderers/common/Renderer.js @@ -1522,6 +1522,8 @@ class Renderer { const previousRenderObjectFunction = this._currentRenderObjectFunction; const previousHandleObjectFunction = this._handleObjectFunction; + this.lighting.beginRender( scene ); + // this._callDepth ++; @@ -1748,6 +1750,8 @@ class Renderer { this._currentRenderObjectFunction = previousRenderObjectFunction; this._handleObjectFunction = previousHandleObjectFunction; + this.lighting.finishRender( scene ); + // this._callDepth --; diff --git a/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js b/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js index 9077bc2cfa4d9b..d6dca8d8237c9b 100644 --- a/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +++ b/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js @@ -877,6 +877,9 @@ class WebGLTextureUtils { const srcFramebuffer = srcRenderContextData.framebuffers[ srcTextureData.cacheKey ]; const dstFramebuffer = dstRenderContextData.framebuffers[ dstTextureData.cacheKey ]; + const prevReadFramebuffer = state.currentBoundFramebuffers[ gl.READ_FRAMEBUFFER ] ?? null; + const prevDrawFramebuffer = state.currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] ?? null; + state.bindFramebuffer( gl.READ_FRAMEBUFFER, srcFramebuffer ); state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, dstFramebuffer ); @@ -894,8 +897,8 @@ class WebGLTextureUtils { } - state.bindFramebuffer( gl.READ_FRAMEBUFFER, null ); - state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null ); + state.bindFramebuffer( gl.READ_FRAMEBUFFER, prevReadFramebuffer ); + state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, prevDrawFramebuffer ); } else if ( srcLevel !== 0 || srcTexture.isRenderTargetTexture || backend.has( srcTexture ) ) { @@ -905,6 +908,9 @@ class WebGLTextureUtils { if ( this._srcFramebuffer === null ) this._srcFramebuffer = gl.createFramebuffer(); if ( this._dstFramebuffer === null ) this._dstFramebuffer = gl.createFramebuffer(); + const prevReadFramebuffer = state.currentBoundFramebuffers[ gl.READ_FRAMEBUFFER ] ?? null; + const prevDrawFramebuffer = state.currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] ?? null; + // bind the frame buffer targets state.bindFramebuffer( gl.READ_FRAMEBUFFER, this._srcFramebuffer ); state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, this._dstFramebuffer ); @@ -949,9 +955,9 @@ class WebGLTextureUtils { } - // unbind read, draw buffers - state.bindFramebuffer( gl.READ_FRAMEBUFFER, null ); - state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null ); + // restore previous read, draw framebuffer bindings + state.bindFramebuffer( gl.READ_FRAMEBUFFER, prevReadFramebuffer ); + state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, prevDrawFramebuffer ); } else {