Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 11 additions & 15 deletions src/nodes/display/ViewportDepthTextureNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,23 @@ class ViewportDepthTextureNode extends ViewportTextureNode {
*
* @param {Node} [uvNode=screenUV] - The uv node.
* @param {?Node} [levelNode=null] - The level node.
* @param {?DepthTexture} [depthTexture=null] - A depth texture. If not provided, uses a shared depth texture.
*/
constructor( uvNode = screenUV, levelNode = null ) {
constructor( uvNode = screenUV, levelNode = null, depthTexture = null ) {

if ( _sharedDepthbuffer === null ) {
if ( depthTexture === null ) {

_sharedDepthbuffer = new DepthTexture();
if ( _sharedDepthbuffer === null ) {

}
_sharedDepthbuffer = new DepthTexture();

super( uvNode, levelNode, _sharedDepthbuffer );
}

}
depthTexture = _sharedDepthbuffer;

/**
* Overwritten so the method always returns the unique shared
* depth texture.
*
* @return {DepthTexture} The shared depth texture.
*/
getTextureForReference() {
}

return _sharedDepthbuffer;
super( uvNode, levelNode, depthTexture );

}

Expand All @@ -62,6 +57,7 @@ export default ViewportDepthTextureNode;
* @function
* @param {?Node} [uvNode=screenUV] - The uv node.
* @param {?Node} [levelNode=null] - The level node.
* @param {?DepthTexture} [depthTexture=null] - A depth texture. If not provided, a depth texture is created automatically.
* @returns {ViewportDepthTextureNode}
*/
export const viewportDepthTexture = /*@__PURE__*/ nodeProxy( ViewportDepthTextureNode ).setParameterLength( 0, 2 );
export const viewportDepthTexture = /*@__PURE__*/ nodeProxy( ViewportDepthTextureNode ).setParameterLength( 0, 3 );
25 changes: 18 additions & 7 deletions src/nodes/display/ViewportTextureNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,12 @@ class ViewportTextureNode extends TextureNode {
}

/**
* This methods returns a texture for the given render target reference.
* This methods returns a texture for the given render target or canvas target reference.
*
* To avoid rendering errors, `ViewportTextureNode` must use unique framebuffer textures
* for different render contexts.
*
* @param {?RenderTarget} [reference=null] - The render target reference.
* @param {?(RenderTarget|CanvasTarget)} [reference=null] - The render target or canvas target reference.
* @return {Texture} The framebuffer texture.
*/
getTextureForReference( reference = null ) {
Expand Down Expand Up @@ -144,9 +144,13 @@ class ViewportTextureNode extends TextureNode {

updateReference( frame ) {

const renderTarget = frame.renderer.getRenderTarget();
const renderer = frame.renderer;
const renderTarget = renderer.getRenderTarget();
const canvasTarget = renderer.getCanvasTarget();

this.value = this.getTextureForReference( renderTarget );
const reference = renderTarget ? renderTarget : canvasTarget;

this.value = this.getTextureForReference( reference );

return this.value;

Expand All @@ -156,20 +160,27 @@ class ViewportTextureNode extends TextureNode {

const renderer = frame.renderer;
const renderTarget = renderer.getRenderTarget();
const canvasTarget = renderer.getCanvasTarget();

if ( renderTarget === null ) {
const reference = renderTarget ? renderTarget : canvasTarget;

if ( reference === null ) {

renderer.getDrawingBufferSize( _size );

} else if ( reference.getDrawingBufferSize ) {

reference.getDrawingBufferSize( _size );

} else {

_size.set( renderTarget.width, renderTarget.height );
_size.set( reference.width, reference.height );

}

//

const framebufferTexture = this.getTextureForReference( renderTarget );
const framebufferTexture = this.getTextureForReference( reference );

if ( framebufferTexture.image.width !== _size.width || framebufferTexture.image.height !== _size.height ) {

Expand Down
44 changes: 31 additions & 13 deletions src/renderers/common/Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -456,13 +456,12 @@ class Renderer {
this._transparentSort = null;

/**
* The framebuffer target.
* Cache of framebuffer targets per canvas target.
*
* @private
* @type {?RenderTarget}
* @default null
* @type {Map<CanvasTarget, RenderTarget>}
*/
this._frameBufferTarget = null;
this._frameBufferTargets = new Map();

const alphaClear = this.alpha === true ? 0 : 1;

Expand Down Expand Up @@ -1341,9 +1340,11 @@ class Renderer {
const { width, height } = this.getDrawingBufferSize( _drawingBufferSize );
const { depth, stencil } = this;

let frameBufferTarget = this._frameBufferTarget;
const canvasTarget = this._canvasTarget;

if ( frameBufferTarget === null ) {
let frameBufferTarget = this._frameBufferTargets.get( canvasTarget );

if ( frameBufferTarget === undefined ) {

frameBufferTarget = new RenderTarget( width, height, {
depthBuffer: depth,
Expand All @@ -1359,7 +1360,19 @@ class Renderer {

frameBufferTarget.isPostProcessingRenderTarget = true;

this._frameBufferTarget = frameBufferTarget;
const dispose = () => {

canvasTarget.removeEventListener( 'dispose', dispose );

frameBufferTarget.dispose();

this._frameBufferTargets.delete( canvasTarget );

};

canvasTarget.addEventListener( 'dispose', dispose );

this._frameBufferTargets.set( canvasTarget, frameBufferTarget );

}

Expand All @@ -1377,8 +1390,6 @@ class Renderer {

}

const canvasTarget = this._canvasTarget;

frameBufferTarget.viewport.copy( canvasTarget._viewport );
frameBufferTarget.scissor.copy( canvasTarget._scissor );
frameBufferTarget.viewport.multiplyScalar( canvasTarget._pixelRatio );
Expand Down Expand Up @@ -2034,7 +2045,7 @@ class Renderer {
* Defines the viewport.
*
* @param {number | Vector4} x - The horizontal coordinate for the upper left corner of the viewport origin in logical pixel unit.
* @param {number} y - The vertical coordinate for the upper left corner of the viewport origin in logical pixel unit.
* @param {number} y - The vertical coordinate for the upper left corner of the viewport origin in logical pixel unit.
* @param {number} width - The width of the viewport in logical pixel unit.
* @param {number} height - The height of the viewport in logical pixel unit.
* @param {number} minDepth - The minimum depth value of the viewport. WebGPU only.
Expand Down Expand Up @@ -2410,7 +2421,11 @@ class Renderer {
this._renderContexts.dispose();
this._textures.dispose();

if ( this._frameBufferTarget !== null ) this._frameBufferTarget.dispose();
for ( const canvasTarget of this._frameBufferTargets.keys() ) {

canvasTarget.dispose();

}

Object.values( this.backend.timestampQueryPool ).forEach( queryPool => {

Expand Down Expand Up @@ -2512,8 +2527,11 @@ class Renderer {
this.setOutputRenderTarget( null );
this.setRenderTarget( null );

this._frameBufferTarget.dispose();
this._frameBufferTarget = null;
for ( const canvasTarget of this._frameBufferTargets.keys() ) {

canvasTarget.dispose();

}

}

Expand Down
132 changes: 132 additions & 0 deletions test/unit/src/nodes/display/ViewportDepthTextureNode.tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { viewportDepthTexture } from '../../../../../src/nodes/display/ViewportDepthTextureNode.js';
import { DepthTexture } from '../../../../../src/textures/DepthTexture.js';
import { RenderTarget } from '../../../../../src/core/RenderTarget.js';

export default QUnit.module( 'Nodes', () => {

QUnit.module( 'Display', () => {

QUnit.module( 'ViewportDepthTextureNode', () => {

// DEPTH TEXTURE CACHING
QUnit.module( 'Depth Texture Caching', () => {

QUnit.test( 'getTextureForReference returns shared buffer for null reference', ( assert ) => {

const node = viewportDepthTexture();
const texture = node.getTextureForReference( null );

assert.strictEqual(
texture, node.defaultFramebuffer,
'null reference should return the shared depth buffer'
);

} );

QUnit.test( 'different references get independent cached depth textures', ( assert ) => {

const node = viewportDepthTexture();

// Create mock canvas targets (simulating different canvases)
const canvasTarget1 = { isCanvasTarget: true, id: 1 };
const canvasTarget2 = { isCanvasTarget: true, id: 2 };

// Get depth textures for each reference
const depthTex1 = node.getTextureForReference( canvasTarget1 );
const depthTex2 = node.getTextureForReference( canvasTarget2 );

// CRITICAL: Different references must get different textures
assert.notStrictEqual(
depthTex1, depthTex2,
'Different CanvasTarget references MUST get different cached depth textures'
);

// Both should be DepthTexture instances
assert.ok(
depthTex1 instanceof DepthTexture,
'Cached texture for canvasTarget1 should be a DepthTexture'
);
assert.ok(
depthTex2 instanceof DepthTexture,
'Cached texture for canvasTarget2 should be a DepthTexture'
);

// Neither should be the shared buffer (they should be clones)
assert.notStrictEqual(
depthTex1, node.defaultFramebuffer,
'Cached texture should not be the shared default buffer'
);
assert.notStrictEqual(
depthTex2, node.defaultFramebuffer,
'Cached texture should not be the shared default buffer'
);

} );

QUnit.test( 'same reference returns same cached depth texture', ( assert ) => {

const node = viewportDepthTexture();

const canvasTarget = { isCanvasTarget: true };

// Get texture twice for same reference
const depthTex1 = node.getTextureForReference( canvasTarget );
const depthTex2 = node.getTextureForReference( canvasTarget );

assert.strictEqual(
depthTex1, depthTex2,
'Same reference should return the same cached depth texture'
);

} );

// Test with RenderTargets
QUnit.test( 'RenderTargets get independent cached depth textures', ( assert ) => {

const node = viewportDepthTexture();

const renderTarget1 = new RenderTarget( 512, 512 );
const renderTarget2 = new RenderTarget( 256, 256 );

const depthTex1 = node.getTextureForReference( renderTarget1 );
const depthTex2 = node.getTextureForReference( renderTarget2 );

assert.notStrictEqual(
depthTex1, depthTex2,
'Different RenderTargets MUST get different cached depth textures'
);

// Clean up
renderTarget1.dispose();
renderTarget2.dispose();

} );

// Test mixed CanvasTarget and RenderTarget references
QUnit.test( 'CanvasTarget and RenderTarget get independent caches', ( assert ) => {

const node = viewportDepthTexture();

const canvasTarget = { isCanvasTarget: true };
const renderTarget = new RenderTarget( 512, 512 );

const canvasDepthTex = node.getTextureForReference( canvasTarget );
const renderDepthTex = node.getTextureForReference( renderTarget );

assert.notStrictEqual(
canvasDepthTex, renderDepthTex,
'CanvasTarget and RenderTarget MUST get different cached depth textures'
);

// Clean up
renderTarget.dispose();

} );

} );

} );

} );

} );
Loading