With no mods, I get 64 for my system, and 84 for the old system. This is probably mostly due to my system rendering more verts. Part of it is due to the old system having a much simpler task when deciding what mods need to be evaluated, and generally having fewer types of mods to evaluate.
In this video you can watch the frame rate drop to ~44 as I turn on more mods. (you can also see poor behavior like drunk having a moving effect while the game is paused)
If I use a sine wave mod on every aspect of the note transform and alpha and glow, like this:
for i, col in ipairs(newfields[pn]:get_columns()) do
for n, getter in ipairs{
"get_note_pos_x", "get_note_pos_y", "get_note_pos_z",
"get_note_rot_x", "get_note_rot_y", "get_note_rot_z",
"get_note_zoom_x", "get_note_zoom_y", "get_note_zoom_z",
"get_note_alpha", "get_note_glow"} do
local mod= col[getter](col)
mod:add_mod{"ModFunctionType_Sine", {"ModInputType_YOffset", 1/64}, i, 1, 0}
end
end
I get ~44 fps in the new system. The visual appearance is rather different, but it's the same idea of performing lots of computation for every note.
Also notable is that I'm measuring this on a debug build. Release builds tend to run substantially faster.
I use 8 fullscreen holds for my test case because it's the worst case scenario. If the worst case is acceptable, then the common and best cases will take care of themselves.
Holds are the worst case because the engine has to calculate many verts to have the shape of the hold affected by the mods. In the old system, a hold body is a symmetric quad strip. One mod evaluation every 16 pixels, to calculate 3 verts, which comes out to 4 triangles each step. If you turn on Bumpy or Twirl, it switches to one 4 pixels per step. Each step is like rendering a note, it needs position, alpha, and glow. (there's a slight gain from ignoring x and z rotation for hold steps)
My hold rendering is similar, but I always use 4 pixels per step because the abstraction of the mod system means it's not easy to answer whether the extra smoothness is worth the cost. I use a normal quad strip instead of a symmetric quad strip, which means half the triangle count for the same number of steps. (but with no mods, I make 4x the steps, so the end result is 2x the triangle count)
In the end, it comes down to doing more in the new system. The field has 16 mods for itself (pos, rot, zoom, receptor and explosion alpha and glow, fov, vanish x and y), and each column has 35 mods (time offset, quantization multiplier and offset, speed, lift trail length, reverse offset, reverse scale, center percent, note transform, column transform, hold normal, note alpha and glow, receptor alpha and glow, explosion alpha and glow). Only the note ones are actually evaluated for every note, but it all adds up.