Page 1 of 2

RenderRadius and sliced rendering

Posted: Sun Feb 14, 2021 7:21 pm
by dpJudas
I have this branch that is 95% ready to be offered as a PR to GZDoom. It will significantly improve the performance of the software renderer all over. I am yet to play a map that didn't play smooth at 60 fps in 1920x1080 on my CPU. I played things like Frozen Time (*), Eviternity, Brigandine and Square (episode 1).

However, there is one problem left which is the render radius of sprites. This screenshot illustrates the problem:



The black bars shows each render slice drawn by individual threads in the software renderer. My CPU has 16C/32T and therefore has 32 slices on the screenshot. If you look at the tree in the center you'll see that it is missing on two of the slices. This is because the value returned by AActor::RenderRadius() is too small. The slices where the tree is missing doesn't see the sectors that is touched by the render radius (the touching_renderthings list).

Question is, how to fix this properly? For it to work reliably the radius has to be the correct (worst case) visual radius of the thing sprite. Can this be calculated and returned by AActor?

*) With dynamic lights disabled, that is.

Re: RenderRadius and sliced rendering

Posted: Sun Feb 14, 2021 10:29 pm
by Rachael
One idea might be to add a new renderflag for every actor (that does not get exposed to scripting, since it would be used internally) that the renderer clears after every frame. Before rendering begins, each actor can be checked to see if it is within the camera's frame - and if so, then rendering the sprite's column might be forceable.

This bug is suggesting that with the current mainline version of the software renderer (and possibly even with the hardware renderer as well), the tree will disappear if it is slightly off screen enough, which indicates a problem with the actor's actual definition, which you can't really do much about.

This may help you, for figuring out if something is properly in-frame or not, I don't know, but hopefully it gives something:
https://en.wikipedia.org/wiki/Angular_diameter

Re: RenderRadius and sliced rendering

Posted: Mon Feb 15, 2021 2:41 am
by Graf Zahl
dpJudas wrote:I have this branch that is 95% ready to be offered as a PR to GZDoom. It will significantly improve the performance of the software renderer all over. I am yet to play a map that didn't play smooth at 60 fps in 1920x1080 on my CPU. I played things like Frozen Time (*), Eviternity, Brigandine and Square (episode 1).
How does it fare with 4 cores? That'd be a lot more interesting because it's the most common configuration.

Re: RenderRadius and sliced rendering

Posted: Mon Feb 15, 2021 5:13 am
by dpJudas
Graf Zahl wrote:How does it fare with 4 cores? That'd be a lot more interesting because it's the most common configuration.
With a 4C/8T setup (by restricting my current CPU to use only that, since I don't have such a computer anymore) the numbers are:



While 4 core is the dominant count, 38% of Steam's users got more than that. Even so, I think 53 fps for Frozen Time is a respectable number for the software renderer on such CPUs.
Rachael wrote:This bug is suggesting that with the current mainline version of the software renderer (and possibly even with the hardware renderer as well), the tree will disappear if it is slightly off screen enough, which indicates a problem with the actor's actual definition, which you can't really do much about.
Yes, the tree will appear if it is slightly off screen in the mainline version too. It is just a lot more tricky to trigger as the sprites are billboarded. The real problem here is really that the RenderRadius value is part of the definition at all. No other sane engine lets the user guesstimate what the bounding sphere is. If you look at the file format of any mainstream engine you'll see this data is always automatically calculated. Not only does that always work, it also makes it far more efficient as the radius will never be too large.
Rachael wrote:One idea might be to add a new renderflag for every actor (that does not get exposed to scripting, since it would be used internally) that the renderer clears after every frame. Before rendering begins, each actor can be checked to see if it is within the camera's frame - and if so, then rendering the sprite's column might be forceable.
If getting the shared code to calculate the correct RenderRadius is indeed too complicated then I will have to resort to such tricks. I wouldn't use a renderflag for it, but it would mean all my threads needs to synchronize which sprites they saw. Any kind of synchronization between the slices is very bad for performance which is why I'd rather have renderradius actually be properly implemented. But if that's not in the cards then I guess I'll have to resort to such an alternative.

Re: RenderRadius and sliced rendering

Posted: Mon Feb 15, 2021 5:35 am
by drfrag
But is the RenderRadius defined for that actor? The default is 0 so in most cases it will be equal to the Radius if i'm not mistaken. What happens if it's bigger than the radius let's say about 150%?

Re: RenderRadius and sliced rendering

Posted: Mon Feb 15, 2021 5:38 am
by Graf Zahl
dpJudas wrote: Yes, the tree will appear if it is slightly off screen in the mainline version too. It is just a lot more tricky to trigger as the sprites are billboarded. The real problem here is really that the RenderRadius value is part of the definition at all. No other sane engine lets the user guesstimate what the bounding sphere is. If you look at the file format of any mainstream engine you'll see this data is always automatically calculated. Not only does that always work, it also makes it far more efficient as the radius will never be too large.
Yes, correct, but the main problem is that the play engine needs to know the size beforehand to properly link the sprite into its sector lists which are used for rendering.
The original was even worse - it only considered the center point with no radius at all. Having the render radius was a huge improvement already.

@drfrag: If render radius is not defined, actor radius is used.

Re: RenderRadius and sliced rendering

Posted: Mon Feb 15, 2021 5:52 am
by drfrag
Of course it's not defined, i take that's eviternity. I meant using the maximum of renderradius and radius*1.5.

Re: RenderRadius and sliced rendering

Posted: Mon Feb 15, 2021 5:57 am
by Rachael
Maybe it might be possible that when the sprite sets and/or model definitions are being installed for an actor (on startup), that the render radius could be calculated right then and there?

For each frame, and each rotation, check which is highest, one of: {LastRenderRadius, offsetX, sizeX - offsetX}

That would likely get the highest possible render radius for an actor if its sprite frames are loaded at startup.

Re: RenderRadius and sliced rendering

Posted: Mon Feb 15, 2021 6:17 am
by dpJudas
drfrag wrote:Of course it's not defined, i take that's eviternity. I meant using the maximum of renderradius and radius*1.5.
I tried using such hacks. It did work for some of the trees, but for others (like the one on the screenshot) I had to use a huge multiplier. How is the radius calculated anyway? Is it part of the definition?
Rachael wrote:Maybe it might be possible that when the sprite sets and/or model definitions are being installed for an actor (on startup), that the render radius could be calculated right then and there?
The ideal is the maximum radius for the sum of sprites (with offset) currently part of the animation (all frames in all directions). That way it only needs to recalculate it if the sprite changes to something else. In theory it should be calculable. I'm just not sure how hard it is to do in practice. :)

Re: RenderRadius and sliced rendering

Posted: Mon Feb 15, 2021 6:38 am
by Graf Zahl
You cannot reliably determine this up front. You'd have to check all known sprites the actor may use at any random point in time, including all rotations.
Scanning the states is not a trivial thing due to inheritance and the ability to set sprites at run time that are not known by scanning the data.
Let's also not forget actor scale and possible model replacements that all need to be factored in here. So the only place where you can do something would be the SetState function - but if this needs to constantly muck around with the sector lists to update the sprite it may cause some secondary problems elsewhere.

Re: RenderRadius and sliced rendering

Posted: Mon Feb 15, 2021 6:42 am
by dpJudas
Okay, thanks for ruling that out. I'll have to find some other plan then. :)

Re: RenderRadius and sliced rendering

Posted: Mon Feb 15, 2021 6:49 am
by Graf Zahl
What I think can be done would be to check the spawn sprite (all rotations, of course) and if that is larger than the defined render radius, expand it. That should catch the vast majority of cases already. And this can be done outside the game on the static actor info data.

Re: RenderRadius and sliced rendering

Posted: Mon Feb 15, 2021 7:16 am
by dpJudas
Hmm, yes that should probably do the trick. The rendering glitch is already pretty rare and honestly I'd personally even trade the current glitch on those maps for the extra performance. I just know that while all current glitches are accepted, if I introduce a new one it will trigger someone's OCD and they'll create a bug report about it. :p

Re: RenderRadius and sliced rendering

Posted: Mon Feb 15, 2021 7:19 am
by Graf Zahl
Yeah, very likely to happen...

Re: RenderRadius and sliced rendering

Posted: Mon Feb 15, 2021 8:28 am
by Gez
Graf Zahl wrote:You cannot reliably determine this up front. You'd have to check all known sprites the actor may use at any random point in time, including all rotations.
Scanning the states is not a trivial thing due to inheritance and the ability to set sprites at run time that are not known by scanning the data.
True; however for the vast majority of cases, it would be good enough -- very few decorations have such complex coding. You may get a few frames of looping animations for things like braziers for example. Inheritance can be addressed by also inheriting the parent's render radius if it's larger.