Postprocessing: SSAO broken on windows

Created on 23 Sep 2020  路  36Comments  路  Source: vanruesc/postprocessing

This is how it looks on my machine:

Screenshot 2020-09-23 at 20 53 51

And this happens on windows:

200923_215241_7VLwgkfkk3

the first one runs 60fps, the other 2fps, it seems to really struggle for some reason.

do you know what it could be? i have it online here: http://warm-vessel.surge.sh and here's a codesandbox: https://codesandbox.io/s/lllt8?file=/src/App.js

the AO config:

<EffectComposer multisampling={0}>
  <SSAO samples={25} intensity={60} luminanceInfluence={0.5} radius={10} scale={0.5} bias={0.5} />
  <SMAA edgeDetectionMode={EdgeDetectionMode.DEPTH} />
</EffectComposer>

These props will overwrite the following default props:

new SSAOEffect(camera, normalPass.renderTarget.texture, {
  blendFunction: BlendFunction.MULTIPLY,
  samples: 30,
  rings: 4,
  distanceThreshold: 1.0,
  distanceFalloff: 0.0,
  rangeThreshold: 0.5,
  rangeFalloff: 0.1,
  luminanceInfluence: 0.9,
  radius: 20,
  scale: 0.5,
  bias: 0.5,
  ...props,
}),

the high intensity is intentional, im going for a pixelated raytraced look emulating soft shadows with AO.

driver issue intel

Most helpful comment

I think I found the reason why the powerPreference setting is ignored in your app: https://www.khronos.org/webgl/public-mailing-list/public_webgl/1703/msg00022.php explains that the canvas needs to have event listeners for webglcontextlost and webglcontextrestored set prior to the WebGL context creation or else the powerPreference setting will be ignored. Your app appears to create a Canvas without setting these listeners.

ThreeJS sets the listeners correctly if you don't provide your own canvas. See https://github.com/mrdoob/three.js/blob/33acbbef6b7cd6afa98e1cf6f02d3f23aaf5bfa0/src/renderers/WebGLRenderer.js#L200-L203 and https://github.com/mrdoob/three.js/pull/12753 for details.

All 36 comments

do you know what it could be?

No idea, sorry. I get 60 FPS on my Windows 10 machine with both Firefox (81.0) and Chrome (85.0.4183.121):

perf

strange, i use mac so i can't test but 2 of 2 people using windows i sent it to had that issue. i think ive seen the inverted AO before, could it be caused by wrong config somehow?

or can they send me some data that could track down the issue?

or can they send me some data that could track down the issue?

Check if there are any console messages. Also make sure that they don't have hardware-acceleration disabled. Get their WebGL report for both WebGL 1 and WebGL 2. Check if "Major Performance Caveat" says "yes".

Massive performance drops are usually caused by too many polygons, too many draw calls, too much overdraw, repeated shader recompilations or frequent frame buffer changes, but none of these issues seem to be present in your app.

could it be caused by wrong config somehow

The only parameters that directly affect performance are samples and width,height or resolutionScale. I noticed that you're setting scale to 0.5, but the SSAOEffect doesn't have a scale parameter. You probably meant to use resolutionScale.

he sent me this @vanruesc

Hey, I think I found the problem
My laptop has two graphics mode

  • Hybrid (switching between Intel graphics and Nvidia depending on load)
  • Discrete GPU (using RTX2070 for everything)

So in this case I think because it was on hybrid mode and I was just using "browser" it must have thought I don't need GPU for it
Also maybe that AO thing isn't supported with Intel graphics?
Because I switched to discreet GPU mode, getting full fps and background isn't grey

I'm not 100% sure, but seems likely to be the case

so, it seems to be related to hardware acc, if isn't on ao won't function correctly?

if isn't on pp won't function correctly?

Post processing filters are executed in addition to the normal rendering pipeline and inherently require lots of graphics processing power. Integrated graphics usually don't have the pixel throughput to process fullscreen effects efficiently.

The WebGL setting powerPreference: 'high-performance' is supposed to tell the browser to use the discrete GPU, but apparently Windows doesn't want to comply.

is there something that would allow me to detect this so that i can serve them a scene without effects?

You could also try to adjust SSAO parameters based on measured FPS. If you lower the sample count and/or resolution, the integrated graphics might be able to render the effect at a reasonable framerate.

I think I found the reason why the powerPreference setting is ignored in your app: https://www.khronos.org/webgl/public-mailing-list/public_webgl/1703/msg00022.php explains that the canvas needs to have event listeners for webglcontextlost and webglcontextrestored set prior to the WebGL context creation or else the powerPreference setting will be ignored. Your app appears to create a Canvas without setting these listeners.

ThreeJS sets the listeners correctly if you don't provide your own canvas. See https://github.com/mrdoob/three.js/blob/33acbbef6b7cd6afa98e1cf6f02d3f23aaf5bfa0/src/renderers/WebGLRenderer.js#L200-L203 and https://github.com/mrdoob/three.js/pull/12753 for details.

yes, turns out i do call getcontext before these two events, never knew that was wrong

const temp = new WebGLRenderer({
  powerPreference: 'high-performance',
  canvas: canvasRef.current,
  context: props.gl2 ? (canvasRef.current.getContext('webgl2', params) as WebGLRenderingContext) : undefined,
  ...params,
})

i think i have a repro: https://codesandbox.io/s/react-three-fiber-v5-forked-lns84?file=/src/App.js it shows that gray bg even on my mac.

Screenshot 2020-09-27 at 11 46 08

this is using powerPref high and doesnt access the canvas context before having these listeners. i included the full react-postprocessing set up in the SSAO component that that it's more clear which parameters it sets.

That setup works fine on my system (Win10, NVIDIA GTX 1060, driver version 456.38):

ssao-win10

The screenshot you posted looks like there's something wrong with either the depth texture or the normal texture. Can you check what those textures look like on your system? I think you can use <Depth> to render depth, but I don't know how to render normals with react-postprocessing.

I've also tweaked the SSAO parameters a little bit in this fork, but I couldn't reproduce the bug.

@drcmda any update on this? It would help to see what the scene depth & normals look like on your system.

I had the same issue in a project even though the SSAO demo worked fine for me. I found out that you can replicate that issue when you pass a value like null as the normal texture to the SSAO effect instead of the actual normal pass rendertarget texture and don't use a normalDepthBuffer in the SSAO effect. In my case I used a normal pass and passed its rendertarget texture but had it still give me that wrong gray AO. It turns out I forgot to add the normal pass to the composer. Since the normal pass wasn't updated then a plain white texture was used in the SSAO shader which is probably the reason why the shader then gave these distorted results (due to an incorrect normal texture). So make sure the normal pass updates and that the normal pass's rendertarget texture is correct (e.g. not plain white).

the weird thing is, that demo now runs fine again. it seems to be related by my computer switching gfx cards. similar to the reports i got. sometimes my system gets really slow and it switches from dedicated to integrated. i dont think it does anything out of the ordinary with normal textures.

it creates the composer, adds a render pass and then a normal pass

        // Initialize composer
        const effectComposer = new EffectComposer(gl, {
          depthBuffer,
          stencilBuffer,
          multisampling: isWebGL2Available() ? multisampling : 0,
          frameBufferType,
        })
        // Add render pass
        effectComposer.addPass(new RenderPass(scene, camera))
        // Create normal pass
        const pass = new NormalPass(scene, camera)
        effectComposer.addPass(pass)

which it keeps and forwards it to effects that may need it

new SSAOEffect(camera, normalPass.renderTarget.texture, {
        blendFunction: BlendFunction.MULTIPLY,
        samples: 30,

i am looking for something now that would allow me to switch between gfx cards manually to see if it's really that.

@0beqz exactly, that's also why I wanted to see depth & normals on the failing system.

@drcmda alright, let me know if you find out more.

@vanruesc so, today it decided to look weird again for some reason and i took the opportunity to export depth and normals. i also changed the demo back to pure postprocessing: https://codesandbox.io/s/react-three-fiber-v5-forked-lns84?file=/src/Post.js

the is how it renders:
Screenshot 2020-10-21 at 12 13 04

normals:
Screenshot 2020-10-21 at 12 12 48

depth:
Screenshot 2020-10-21 at 12 10 53

GPU info:

tier: "2"
type: "BENCHMARK - intel hd graphics p630"

the crazy thing is, if i click fullscreen in codesandbox it looks ok. it then uses the dedicated gpu:

tier: "2"
type: "BENCHMARK - amd radeon pro 555"

Your normals and depth values look fine so these shouldn't be causing problems. The normals only appear to overlap incorrectly because they are being rendered to the screen which doesn't have a depth buffer in this setup. I was hoping for at least one of these textures to give us some hints as to why the effect is failing.

Just to confirm: are there any messages in the console when the effect is failing?

I've looked through the SSAO shaders again, but couldn't find anything sticking out as potentially dangerous. This seems to be either a hardware/driver bug or a browser issue. What browser are you using and what's your Intel Graphics driver version?

Unlikely to be the cause, but possibly related: https://www.khronos.org/webgl/wiki/BlacklistsAndWhitelists & https://bugzilla.mozilla.org/show_bug.cgi?id=628129

the console is empty, nothing unusual, no errors or warnings. i am on the latest stable chrome Version 87.0.4280.20 (Official Build) beta (x86_64),

Intel UHD Graphics 630:

  Chipset Model:    Intel UHD Graphics 630
  Type: GPU
  Bus:  Built-In
  VRAM (Dynamic, Max):  1536 MB
  Vendor:   Intel
  Device ID:    0x3e9b
  Revision ID:  0x0000
  Automatic Graphics Switching: Supported
  gMux Version: 5.0.0
  Metal:    Supported, feature set macOS GPUFamily2 v1
  Displays:
Colour LCD:
  Display Type: Built-In Retina LCD
  Resolution:   2880x1800 Retina
  Framebuffer Depth:    24-Bit Colour (ARGB8888)
  Main Display: Yes
  Mirror:   Off
  Online:   Yes
  Automatically Adjust Brightness:  No
  Connection Type:  Internal

but it seems to be a more generic issue since i was first made aware of it by windows users. they confirmed as well that their integrated gpu's couldn't handle the ao.

maybe look at chrome://gpu/ for GPU0 info what GPU is used, with the power preference high-performance in webgl the decided GPU should be used, maybe this is a chrome bug only set this in the fullscreen mode?

Please also check the GPU memory usage via Chrome's task manager.

gpu memory

Screenshot 2020-10-21 at 14 54 23

webgl log messages

Screenshot 2020-10-21 at 14 54 38

gpu status

GPU0 | VENDOR= 0x1002, DEVICE=0x67ef
-- | --
GPU1 | VENDOR= 0x8086, DEVICE=0x3e9b ACTIVE

i don't normally have any gpu troubles. it usually takes the dedicated gpu. but even if it uses the integrated one, it shouldn't cause problem imo. there's just something going on that seems to flip textures for some reason.

Does the problem disappear when you disable MSAA by setting multisampling to 0?

looks like chrome still use the Intel VENDOR= 0x8086, DEVICE=0x3e9b ACTIVE

see the ACTIVE flag at the end

@arpu true, but even then the effect shouldn't fail like this since the driver is up-to-date and the hardware supports WebGL.

The error messages indicate that four different textures are not renderable for some reason. These textures are non-power-of-2 but they don't use mipmapping so this shouldn't be a problem. I wonder why it's possible to render normals and depth, but not SSAO. My current guess is that the GPU is running out of memory due to MSAA and the frame buffers can't be created.

multisampling has no effect unfortunately, should have been 0 anyway since it's using MSAA.

i noticed something really strange, it seems to be related to the background color. the scene is configured like so:

      <Canvas
        gl={{ antialias: false, stencil: false, depth: false, alpha: false }}
        camera={{ position: [0, 0, 15], near: 5, far: 40 }}>
        <color attach="background" args={['white']} />
        <fog attach="fog" args={['white', 10, 40]} />

gl.alpha is set to false, and scene.background is set to white.

if i do this (setClearColor instead of scene.background):

      <Canvas
        concurrent
        gl={{ antialias: false, stencil: false, depth: false, alpha: false }}
        pixelRatio={1.25}
        camera={{ position: [0, 0, 15], near: 5, far: 40 }}
        onCreated={state => state.gl.setClearColor("white")}>
        <fog attach="fog" args={['white', 10, 40]} />

then it works!

i never really understood the difference between clearcolor and scene.background, but can that, someone, affect how pp works?

i was excited too early. this happens when it switches to intel:

Screenshot 2020-10-21 at 15 46 54

the plane draws AO artifacts. doesn't happen with radeon. seems like another problem but related.

difference between clearcolor and scene.background

It would seem that scene.background and gl.setClearColor() do the same thing, but setClearColor supports strings as input. I don't think you can set scene.background to a string. Only Texture, Color, CubeTexture and WebGLCubeRenderTarget are supported.

Postprocessing disables auto clear and the ClearPass simply uses the clear color and clear alpha of the renderer. Other passes such as the NormalPass use override clear colors to clear the normal texture to specific default values like 0x7777ff. I don't know how this would cause render targets to blow up, though.

the plane draws AO artifacts

Could you please show me the normals and depth again? Maybe they look different now.

I didn't notice this before, but the first normal texture screenshot you posted has a white background color which is wrong. The SSAO demo also sets a background color, but this doesn't seem to cause any issues there. Anyway, the NormalPass as well as other passes that use override clear colors should probably disable scene.background temporarily to produce correct results.

Screenshot 2020-10-21 at 17 52 46

Screenshot 2020-10-21 at 18 05 58

depth looks quite ok, normals look off for the plane.

I don't think you can set scene.background to a string.

<color attach="background" args={["white"]} />

is the same as:

parent.background = new THREE.Color("white")

the parent is the default scene.

Thanks for the screenshots and info.

normals look off for the plane

That's because the screen has no depth buffer (gl={{ ..., depth: false, ... }). The actual normal render target has a depth buffer so this is nothing to worry about.

Are the error messages about incomplete frame buffers still appearing after switching to state.gl.setClearColor('white')?

To provide another data point: the example works on my phone (Android 9, ARM Mali G72 MP3):

arm-mali-screenshot

Unfortunately, it seems that we can't fix this in the library. Tagging as driver issue and closing due to inactivity.

If you find out anything that could resolve this, feel free to reopen.

Was this page helpful?
0 / 5 - 0 ratings