@@ -11,7 +11,7 @@ import {
1111} from 'postprocessing'
1212import * as React from 'react'
1313import * as THREE from 'three'
14- import { afterEach , describe , expect , it , vi } from 'vitest'
14+ import { afterEach , beforeEach , describe , expect , it , vi } from 'vitest'
1515import { EffectComposer } from '../EffectComposer'
1616import { ColorAverage } from '../effects/ColorAverage'
1717import { wrapEffect } from '../wrapEffect'
@@ -1462,4 +1462,71 @@ describe('EffectComposer', () => {
14621462 initializeSpy . mockRestore ( )
14631463 } )
14641464 } )
1465+
1466+ describe ( 'sizing' , ( ) => {
1467+ // frameloop is 'never', so frames are advanced by hand. The GL context is mocked, so only
1468+ // the sizing check runs, not the render. The test canvas has no layout, so give it a size
1469+ const renderer = ( ) => root . render ( null ) . getState ( ) . gl
1470+
1471+ beforeEach ( ( ) => renderer ( ) . setSize ( 640 , 400 , false ) )
1472+
1473+ afterEach ( ( ) => {
1474+ renderer ( ) . setPixelRatio ( 1 )
1475+ renderer ( ) . setSize ( 0 , 0 , false )
1476+ } )
1477+
1478+ const mountSized = async ( ) => {
1479+ const ref = React . createRef < EffectComposerImpl > ( )
1480+ const store = await React . act ( async ( ) =>
1481+ root . render (
1482+ < EffectComposer ref = { ref } >
1483+ < WrappedEffectA />
1484+ </ EffectComposer >
1485+ )
1486+ )
1487+ const composer = await waitForComposer ( ref )
1488+ vi . spyOn ( composer , 'render' ) . mockImplementation ( ( ) => { } )
1489+ const frame = ( ) => React . act ( async ( ) => store . getState ( ) . advance ( performance . now ( ) ) )
1490+ await frame ( )
1491+ return { gl : store . getState ( ) . gl , composer, frame, setSize : vi . spyOn ( composer , 'setSize' ) }
1492+ }
1493+
1494+ it ( 'does not resize the composer on frames where nothing changed' , async ( ) => {
1495+ const { frame, setSize } = await mountSized ( )
1496+ await frame ( )
1497+ await frame ( )
1498+ expect ( setSize ) . not . toHaveBeenCalled ( )
1499+ } )
1500+
1501+ it ( 'resizes the composer when only the pixel ratio changes' , async ( ) => {
1502+ const { gl, composer, frame, setSize } = await mountSized ( )
1503+ const cssSize = gl . getSize ( new THREE . Vector2 ( ) )
1504+
1505+ // What r3f's setDpr and drei's AdaptiveDpr do: the CSS size stays, the drawing buffer doesn't
1506+ gl . setPixelRatio ( 2 )
1507+ await frame ( )
1508+
1509+ expect ( setSize ) . toHaveBeenCalledTimes ( 1 )
1510+ expect ( setSize ) . toHaveBeenCalledWith ( cssSize . width , cssSize . height )
1511+ expect ( composer . inputBuffer . width ) . toBe ( cssSize . width * 2 )
1512+ expect ( composer . inputBuffer . height ) . toBe ( cssSize . height * 2 )
1513+
1514+ await frame ( )
1515+ expect ( setSize ) . toHaveBeenCalledTimes ( 1 )
1516+ } )
1517+
1518+ it ( 'shrinks its buffers when the pixel ratio drops' , async ( ) => {
1519+ // e.g. AdaptiveDpr regressing, or the window moving to a 1x display
1520+ renderer ( ) . setPixelRatio ( 2 )
1521+ const { gl, composer, frame } = await mountSized ( )
1522+ const cssSize = gl . getSize ( new THREE . Vector2 ( ) )
1523+ expect ( composer . inputBuffer . width ) . toBe ( cssSize . width * 2 )
1524+
1525+ gl . setPixelRatio ( 1 )
1526+ await frame ( )
1527+
1528+ expect ( composer . inputBuffer . width ) . toBe ( cssSize . width )
1529+ expect ( composer . outputBuffer . width ) . toBe ( cssSize . width )
1530+ } )
1531+ } )
14651532} )
0 commit comments