veldrid / veldrid

A low-level, portable graphics library for .NET.
https://veldrid.dev/
MIT License
2.5k stars 272 forks source link

Vulkan is twice as slow as OpenGL #544

Open WaneOshin opened 6 days ago

WaneOshin commented 6 days ago

Hello everyone.

I am not that experienced with backends but as far as i know vulkan should have atleast the same FPS as OpenGL but testing out the Demo from here and another Sample from Github and my own project, OpenGL(or OpenGLES) runs x2 faster than Vulkan backend without changing any code. Examples : Demo 226fps vs 100fps or MyProject 4800fps vs 2600fps

Is there any reason to this or any way to so called "Fix" this? Thanks

Redhacker1 commented 6 days ago

Are you modifying buffers in any way (say like for instance, changing model matrix?)

WaneOshin commented 5 days ago

Yes I Update View,Projection,Matrices and InstanceBuffer (Models info for rendering like height or radius) each frame before Draw . Why so?

Redhacker1 commented 5 days ago

If you modify a buffer in the middle of the frame, veldrid has to stall the GPU to end and start a new renderpass, update the buffer and then continue drawing commands. That process is slow.

Redhacker1 commented 5 days ago

Look at renderdoc and see if you can identify. That's what it's doing. What I would suggest doing as a workaround is either storing a buffer per object and updating them before you draw the frame. Or use a large buffer of that data that is traversed per instance. I have an example on how to do this on my Minecraft clone core project, I would recommend taking a look at it.

Veldrid doesn't expose the concept of push constants because opengl I believe doesn't expose them, DirectX 11 might not either. So either one of those is your only option

WaneOshin commented 5 days ago

Thanks for the suggestion and reply, but: This isnt just my project though, It happens on veldrids official demo (neo-demo) and other samples i found on the internet! So i dont think its the code...

Redhacker1 commented 4 days ago

Do you mind showing me what drawcalls look like in renderdoc?

Redhacker1 commented 4 days ago

Literally just a screenshot of what renderdoc shows can be immensely helpful

Vulkan on Veldrid has Gotcha's. I am pretty sure Whatever you are having issues with will be shown in what calls are being made.

This is what you want to see on the Vulkan side, anything about RenderPasses is bad. image

EDIT: Addendum after more testing: OpenGL runs worse for me in NeoDemo with my 3070, depending on graphics hardware, your GPU might just suck at running Vulkan. It is not unheard of in older cards. If so nothing more you can do other than "git gud" and get a new GPU or "live with it" and run OpenGL. Vulkan isn't always a free performance boost and you miss some of the advantages of using it running Veldrid anyway. DX11 and OpenGL are more than adaquate for most things.

WaneOshin commented 4 days ago

Thanks this really helped. I installed RenderDoc and this is a single frame: image What am i doing wrong ? i dont understand much...

I Tested NeoDemo again and your right OpenGl does run slower than Vulkan I was testing it on "Debug" (which gives opposite results, my bad)!!!

EDIT: My project still gives "Vulkan slower than OpenGL" fps btw. The neoDemo was fixed though after i put it on "Release" mode.

WaneOshin commented 4 days ago

and this is the code in the "Loop": image Each "Draw" has its own setVertex and UpdateBuffer and Draw ...

Redhacker1 commented 4 days ago

All that begin and end render pass stuff is bad. That being said, I will assume that is immediate mode gui being an issue.

Focusing on your code. The wait for idle is unnecessary, try removing it. It is an unnecessary performance hit but it should affect all apis and not just vulkan

Redhacker1 commented 4 days ago

You don't want to do any updating of the buffers during your draw loop. In order to update the buffer, veldrid has to end the renderpass and start a new one. That implicitly means that you're essentially calling wait for idle every time you update the buffers. Because the GPU has to finish the current render pass before it can start another.

Redhacker1 commented 1 day ago

You still having issues?

WaneOshin commented 11 hours ago

immediate mode gui didnt really affect the fps. I have to rewrite all the code which takes time and implement what you said (so i update buffers in a separate {cl.begin,...,cl.end}?). Thanks alot for the help

WaneOshin commented 5 hours ago

You don't want to do any updating of the buffers during your draw loop. In order to update the buffer, veldrid has to end the renderpass and start a new one. That implicitly means that you're essentially calling wait for idle every time you update the buffers. Because the GPU has to finish the current render pass before it can start another.

how am i supposed to update the buffers then? this is how the samples do it!.... Should i end -> sendCommandList -> begin after every UpdateBuffer I call ?

EDIT: It looks like removing "WaitForIdle" boosted up the vulkan FPS from 2600 to 4000. But its still behind opengl's 4800. OpenGl.rdc : image as you can see it has much fewer commands compared to the vulkan one that I posted earlier (Idk what renderdoc shows im just guessing these are commands).