I'll look into this. Something else I've noticed on the last couple of patches though - when you have certain UI panels open, like the friends list, even without addons your fps can drop dramatically for no apparent reason. Ever seen that?

I ran into this in my map project when I tried to draw very large numbers of textures and font strings at once. Just having them on-screen caused a noticeable dip in the frame rate, but attempting to move the frame they were attached to practically froze the game.

I had created many font strings as labels for various POIs on the map..

And displaying them for the entire continent greatly impacted frame rates.

However, since you could both drag and zoom the map, it quickly became obvious that moving or scaling the frame caused exponentially more of a problem for FPS.

When I adjusted the script to hide the labels while dragging, and showing them when finished, it completely solved the problem. As long as the regions aren't visible while they're being repositioned they have almost no impact on the frame rate.

This leads me to believe that simply recalculating the positions of the regions isn't the problem, but redrawing them every time they move is. Therefor, if you can limit how often they're redrawn you should be able to limit the impact on frame rate.

This may not make any sense, but instead of anchoring your nameplates directly to the existing one, try attaching them to the WorldFrame and using an OnUpdate script to reposition them only once per frame.

The author of kui nameplates uses this method to keep their nameplates pixel perfect, although an unexpected side effect is higher frame rates.

This may not make any sense, but instead of anchoring your nameplates directly to the existing one, try attaching them to the WorldFrame and using an OnUpdate script to reposition them only once per frame.

Isn't once per frame refresh already the speed at which frames and regions are repositioned/redrawn? I don't see how dumping the positioning into a separate OnUpdate script will improve the situation.

Unless, of course, all UI code normally runs on the same thread, and only by using OnUpdate can you allow proper multi-threading...

Or perhaps frame/region positions might simply not be calculated at all when the object is hidden.

You can forget about repositioning the frame OnUpdate without hiding it first, it doesn't seem to make as much of a difference as I thought. On the other hand, this trick seems to make a huge difference.

The only downside is it lags one frame behind the default nameplate, but maybe there's a way to overcome that.

There are 2000 font strings per nameplate in this screenshot, and while it has dropped my frame rate down to around 15 fps I can still smoothly rotate the camera and run around without any issues. Attaching them directly to the nameplate completely freezes the game in this same test.

Thanks semlar. The difference in FPS is hilarious btw. You can even see how the fontstrings move point-by-point.

I never used an OnUpdate script that runs on every frame before though.

So semlars solution to this is:

Instead of putting all your frames on the nameplate itself we create a new frame on the Worldframe that still has a link to the corresponding Blizzard nameplate. On every frame update we hide our plate first, do our calculations and show it thereafter.

Two things in his example will lag you out by a mile.

Adding frames directly to the Blizzard nameplate

Not hiding our new nameplate frame before doing calculations

If you want the fastest nameplates on the planet you need to build them like semlar posted.
To make it clear... on the screenshot are 500 fontstrings per nameplate. Not 5. And it still runs smoothly.

This also has a major bonus. Since we are living in the environment of OnUpdate we can do all the calculations we want. (color calculation etc.)

I know it's not exactly what you were looking for since you still get the fps dip from just having the regions on your screen, but it makes a pretty big difference in playability when you try to rotate the camera around.

The two important things are:

Don't make your frame a child of the nameplate

Hide the frame before you reposition it and show it afterwards

Also I have no idea why this works, so that's probably something to investigate.

I cleaned up the code in my post a little and added some comments to make it more readable.

You can use a different method for detecting the nameplates if you want, this is just how I did it in my example (mostly pulled out of my QuestPlates addon).

There isn't really any reason to use SetScript over HookScript since HookScript will create the script if it doesn't already exist, and you also might want to just create your own frame for the OnUpdate script just to be safe, although I can't think of a reason why that should break.

Oh one more thing, since we are iterating over the WorldFrame children, we might want to create our new frames under a different parent to save a little overhead, for example create a single frame under WorldFrame to use as the parent for all of the rest of the frames.

This gives you a reason to create a frame for the OnUpdate script and also allows you to toggle the visibility for all of the frames at once if you needed to.

Just make sure you factor in the scale if you parent them somewhere else.

As Semlar mentioned, I've been doing the WorldFrame trick with my nameplate addon for a while but for a different purpose. I wanted to manuallly set the position of my nameplates every frame so that I could make sure they were on 1:1 pixels and overcome the UI anti-aliasing issues. I noticed as a result of doing this, and of manually setting the position rather than using something like SetAllPoints, my nameplates had practically no effect on FPS over the default nameplates. Initially it was faster, but I'm not sure if that's the case anymore as I can't :Hide() the default UI elements otherwise I'd break compatibility with other addons.

I mentioned this to the author of TidyPlates a while ago and had the conclusion that what creates the most lag is adding frames as children directly to the default nameplates. I believe he made a test version with his nameplates parented to the WorldFrame and that alone drastically reduced the impact.

Since I'm doing this to make the nameplates pixel-perfect, I obviously have to do a little maths every frame aswell but even with that it still has a positive effect on FPS.

A particularly negative effect I've noticed from doing this is that when using stacking nameplates (the default UI option), if there are too many nameplates displayed and the stacking method "gives up", nameplates will jitter around slightly. This seems to only happen when using stacking, not spreading. That may be a result of my 1:1 code however.

Edit: no such luck with some potential improvements, I'll have to look into this more during my still-in-progress complete rewrite. I have a lot of stuff to look in to.

Do I understand this correctly that the problem is way worse on 5.4 PTR than on 5.3 live? Because I don't get that huge differences in FPS when hiding my namespates on 5.3 live servers (using Tidy Plates Threat Plates).

Oh, you're right. I was actually using the scale of the bar group instead of the actual nameplate because I was experimenting with something.

Apparently the bar is scaled down, not the actual plate frame, so just disregard what I said.

On an unrelated note, I've been working on a way to show friendly nameplates but prevent you from interacting with them because I want to be able to see them without them getting in the way of what you're trying to click on.

Since you can't just :Hide() the nameplate in combat because of secure frame restrictions, I've had to get a little creative with SetCVar('nameplateShowFriends', 0) toggling them on to get the frame positions and immediately back off to prevent mouse interaction.

This actually works, but there is a 2 frame delay before plates appear after toggling them on which isn't a huge deal but it also causes the cursor to blink like crazy while it switches between states. I can probably counter that but I was wondering if anyone had any better ideas for how to do this.