ValveSoftware / openvr

OpenVR SDK
http://steamvr.com
BSD 3-Clause "New" or "Revised" License
6.06k stars 1.27k forks source link

HMD Screen tearing/artifacts #1586

Open LordOfDragons opened 3 years ago

LordOfDragons commented 3 years ago

In my game engine I'm seeing a strange problem with SteamVR. First things first the 3D rendering using OpenVR works. I'm using the render size as requested by OpenVR. I'm rendering the scene then copy it to the left/right eye FBO in a final shader step, then submit both textures to OpenVR. In the HMD and the VRView window a rectangular area is overlayed with garbage flickering wildly as seen in this screenshot of VRView: Screenshot

Using RenderDoc I can verify the left and right eye texture is correct and free of garbage. I can now switch to half-resolution rendering in my game engine and the garbage vanishes. Half-resolution rendering means the scene is rendered in 1/2 size but in the final shader copy (as mentioned above) the scene is upscaled to the size requested by OpenVR. In particular this means no matter if half-res rendering is enabled or not the final FBO submitted to OpenVR is of the exact size no matter if garbage is displayed or not.

Can anybody provide help here?

Hardware: VIVE (not pro or cosmos, the regular one) OS: Linux GenToo 64-Bit Steam: Native Linux version (so no WineHQ or similar)

What I've tried already:

Using two left/right FBOs alternating between them after each submit. The same garbage shows.
Using glFinish() right after submit to ensure presenting is finished before continueing. Same garbage

Observations:

At one time I've seen my desktop mouse pointer in the HMD rendered over the 3D scene. Can it be the garbage is some kind of 2D overlay originating from SteamVR causing troubles?
LordOfDragons commented 3 years ago

Additional informations:

I've tested now on two machines, one with GenToo (AMD) and one with Ubuntu (nVidia). On GenToo the screenshot above applies with flickering garbage. On Ubuntu the same area is blocked in the HMD but with a black rectangle not flickering.

In both cases RenderDoc shows the left and right eye image to be correct (content and size). I've checked examples on the internet and I'm doing the same.

Is there a way to temporarily disable all overlays to see if the tearing is due to overlay malfunctioning? Myself I'm using no overlays.

LordOfDragons commented 3 years ago

Did some more testing. If I do not use the requested size of 1584x1760 but limit it to 1024 (like 922x1024) then the tearing is barely visible. It seems the tearing happens in areas beyond 1024 width or height.

Can it be OpenVR/SteamVR reports the wrong texture size to use as render target for the eyes?

LordOfDragons commented 2 years ago

According to specification the HMD used has a resolution of 1080x1200. OpenVR (SteamVR) though reports 1584x1760 as requested size. This is larger than the HMD can do according to specifications. Can this lead to problems? Does OpenVR/SteamVR report the wrong size and thus fails to composite properly to the HMD?

Rectus commented 2 years ago

According to specification the HMD used has a resolution of 1080x1200. OpenVR (SteamVR) though reports 1584x1760 as requested size. This is larger than the HMD can do according to specifications. Can this lead to problems? Does OpenVR/SteamVR report the wrong size and thus fails to composite properly to the HMD?

This is normal. The runtime has to transform the image to compensate for the lens distortion, and to get approximately the same pixel density in the view center, the resolution has to be bigger. Since you lose the ability to do pixel mapped rendering with this, SteamVR will also further increase the default resolution depending on the GPU performance to get more fidelity.

LordOfDragons commented 2 years ago

What can possibly cause this garbled overlay rectangle on the bottom side? The textures send I can verify with RenderDoc to be correct.

Relevant code locations are:

The call order is:

Basically this means: render left eye -> render right eye -> submit left eye -> submit right eye.

The artifacts appear in both eyes and they are identical.

kisak-valve commented 2 years ago

Hello @LordOfDragons, what video card / driver version are you using? I suspect that https://github.com/ValveSoftware/SteamVR-for-Linux/issues/395 is interfering with your testing and if that's the case, then https://github.com/ValveSoftware/SteamVR-for-Linux/issues/227#issuecomment-520459572 could workaround that issue.

LordOfDragons commented 2 years ago

@kisak-valve The bug report states this behavior happens if the system menu is opened. This is not the case here. This happens during normal in-game rendering without any system menu open nor any overlays active that I know about.

LordOfDragons commented 2 years ago

Using a different test scene I noticed the garbage is not fully random. It seems to compose of parts of the submitted images. I've made a screenshot of it: Screenshot.

It looks to me like a compositing bug in OpenVR/SteamVR.

LordOfDragons commented 2 years ago

Forgot to post the steamVR report: SteamVR Report.

Rectus commented 2 years ago

That looks like it is reading in a lot of garbage data from the GPU side. I think SteamVR uses whatever dimensions that are on the textures you submit, so I'd suggest checking that the textures get set up correctly.

LordOfDragons commented 2 years ago

I don't think so. This is the left eye image as captured by RenderDoc: Left Eye Image.

This is the texture information from RenderDoc: Initial Texture Parameters.

OpenVR requested this time "Render Size: 1640 1824" which is a match.

Here is a RenderDoc screenshot of the compositor call: RenderDoc Compositor Screenshot. As you can see in the lower left this image is the output of the compositor code running in CVRSharedGLTexture::Update(void*, vr::VRTextureBounds_t*, unsigned int, unsigned int, CVRCompositorSharedTextures::CommandBuffer_t*)

I can verify the input to this shader call is my rendered left image and it is correct without garbage. The compositor output though is incorrect. It looks to me like if the compositor uses wrong screen coordinates while rendering causing parts of the HMD texture not being rendered.

LordOfDragons commented 2 years ago

Here is the full draw-call from RenderDoc:


glBlitFramebuffer(Framebuffer 3244, Framebuffer 3250)

readFramebuffer Framebuffer 3244
drawFramebuffer Framebuffer 3250
srcX0         0
srcY0         0
srcX1         1640
srcY1         1824
dstX0         0
dstY0         1824
dstX1         1640
dstY1         0
mask          GL_COLOR_BUFFER_BIT
filter        GL_NEAREST```
Rectus commented 2 years ago

Does the same thing happen with the OpenGL version of the hellovr sample application? It might be a good idea to compare with it to confirm whether the issue is with the application or the runtime.

LordOfDragons commented 2 years ago

I've noticed something. The glBlitFramebuffer call inside OpenVR uses these viewport/scissor settings: 0-15 0 0 1520 950 0 1

The texture though has size 1640x1824 as requested by OpenVR. So OpenVR uses an incorrect glViewport/glScissor call somewhere.

Just to confirm something... OpenVR does not change the requested resolution while running? Because I request the size up-front and create the target.

EDIT: Nope. I checked the FBO used by OpenVR as destination. The texture in there has the same size as the input texture so this can not be the reason.

LordOfDragons commented 2 years ago

Okay. I think I see where this is heading. In my game engine I used glViewport/glScissor with 1520x950 to render to the companion window. It looks like OpenVR does not call glViewport/glScissor during CVRCompositorClient::SubmitWithArrayIndex() call and thus uses whatever viewport/scissor region the rendering application has been using right before calling this method.

To fix this two solutions are possible: 1) Change OpenVR to always call glViewport/glScissor before calling glBlitFramebuffer to ensure the right values are used 2) Update the CVRCompositorClient::Submit() documentation with a warning that applications are required to set glViewport/glScissor to the correct value (to (0,0)-(requestedWidth,requestedHeight)) before calling Submit()

Personally I think solution one should be done but I could live also with solution 2.

Rectus commented 2 years ago

Glad to see you found the issue.

You might still want to check if it replicates on the sample app, since that also seems to render the companion window with a very low resolution without changing glViewport back afterwards.

LordOfDragons commented 2 years ago

I did a final test. The problem is not the missing glViewport but the scissor box. At the time Submit() is called GL_SCISSOR_TEST is enabled. glBlitFramebuffer is affected by the scissor box test so this is why things go wrong.

The fix thus is to call glDisable(GL_SCISSOR_TEST) before calling Submit().

But I think OpenVR should call glDisable(GL_SCISSOR_TEST) as precautionary measure before calling glBlitFramebuffer since otherwise applications need to know about OpenVR internal operations which is bad.