My recollection of Vice City is that the vehicle dynamics model is not particularly realistic but optimized for “fun gameplay with a hint of realism” whereas Papyrus optimized towards “realistic gameplay with a hint of fun”. :D
Our physics engine was deeply, deeply tied to a particular isochronous rate (30 Hz, then later 60Hz, IIRC) with all kinds of hackery to make that happen and divorce rendering rate from physics rate. (On the PSX, we ran physics engine tied to the VBlank.)
Not sure that gonna help much.
I think what you should do instead, port your OpenGL code to OpenGL ES. Specifically, Raspberry Pi 1-3 support GLES 2.0, Pi 4 supports GLES 3.1. As a nice side effect, renderer will become portable to smartphones.
This may or may not be a lot of work, depending how exactly you use OpenGL.
Pi 4 introduced Vulkan as well, but unlike GLES I have not tested it and not sure how good is the support.
1. On the main rendering pass, your code renders stuff mostly back to front. Consider sorting opaque objects by Z and render then front to back. If you do that, early Z rejection gonna save tons of pixel shaders and fill rate. The sorting doesn’t need to be perfect, an approximate will do as well, but with these ~5k draw calls I’m pretty sure even C qsort gonna be adequate on Pi4.
Translucent objects need to be rendered back to front like you’re currently doing.
2. In your pixel shader you often have this code:
if( a < u_alphaRef.x || a >= u_alphaRef.y ) discard;
Where u_alphaRef is [ -1000; +1000 ] i.e. very large interval.Don’t do that. Write another pixel shader for cases when you don’t need alpha tests. GPUs disable some optimizations (early Z rejection is one of them) when you calling discard in GLSL/HLSL.
3. Up to EID 5328, the game rendered the next frame. Starting from EID 5377, the game was finishing rendering of the previous one. That’s a good idea by itself, the problem with that, the temporary texture has size 4096*4096 pixels. Only top-center 3840*2160 portion was actually used. My desktop PC is fast enough to deliver 60 FPS, but on RPi you should not use textures much larger than necessary. All modern GPUs support non-power-of-2 textures, Pi4 included.
4. You are using 2x MSAA for the main pass. At least for my test cases on Pi4 (see e.g. this project https://github.com/Const-me/Vrmac ), even 2x MSAA ruined performance, if you use the same setting on Pi4, I think that contributed the most to the performance issue.
Try to disable MSAA and see what gonna happen. If you’ll find out it helps with the performance but the quality is too bad now, try to implement a cheaper substitute somehow, search the web for FXAA and SMAA keywords.
For shaders I'm never sure if I should do something dynamically or switch to a different shader, but it makes sense of course to kill the alpha test code if it's not used.
As for MSAA, our support for that is pretty rather young and it gives artifacts. I'm actually surprised it's on at all by default...
It’s used, but only for some meshes like vegetation, u_alphaRef was like [ 0.50196, 1000.00 ] for them.
> I'm actually surprised it's on at all by default
I don’t think I have adjusted anything, just built and run your code on Win10 with GL. This doesn’t mean it gonna use the same defaults on Pi, but it might.
It might just be really unhappy with the number of draw calls that you are doing. Looks like you are currently doing a drawcall per mesh; You might need to pack multiple meshes into a single drawcall.
Do you have any idea how many drawcalls per frame you are currently doing?
Last time I profiled something graphically intensive on the pi 4, I found that touching any of the draw state or uniforms between draw calls would trigger an expensive re-validation on the whole pipeline. 50% of my cpu time was spent in the driver.
Of course, the app I was profiling was pushing quite a lot of uniforms per draw call. Your workload might be different, so profile before doing anything drastic.
I recommend building a version of mesa with symbols so you can see exactly where CPU time is spent.
BTW, try prepending `mesa_glthread=true` to your command to see if that gives you a free speed boost.
I don't know if these extensions are available on Pi driver, though.
The problem with graphics programming is that really you need to learn two things simultaneously: how 3d graphics are rendered, and how to use a GPU api. They can both be a significant thing to learn alone, and the complexity of cramming the two into your brain together makes things hard.
I suppose this is because the original developers knew exactly what hardware this would run on and the achievable framerate on the PS2 and so took lots of short-cuts in the code?
Edit: Incredible project by the way.
I hate to say it, but fixed frame rates these days seem very 'lazy'? Obviously depending on use case and hardware.
If you know the game is only going to run on certain hardware, and you make the most money during the launch period of the game, it doesn't make sense to spend time, effort and money on something niche for the future.
[1]: https://www.gamedev.net/articles/programming/math-and-physic... Edit: http://archive.gamedev.net/archive/reference/articles/articl...
- the games do not run particularly well on the raspberry pi (any version really) and I have a feeling it's at least partially due to the OpenGL layer. We could really use someone with how to optimize OpenGL (especially on the pi).
- physics have always been wonky beyond 30fps. I think someone with a good knowledge of game physics could really help us here.