I've just found a funny bug in the HTML5 version.
There's a screen in the game ("Records") that displays the code of all the best solutions of the player, and there's an option to zoom out with Ctrl+wheel. Naturally, when you zoom out there's more text to render, so in the PC version, for my savefile (lots of solutions), frame time increases from 0.8ms (no zoom) to 1.1ms (max zoom out) - nothing to worry about.
The HTML5 version is slower, and frame handling+rendering time without zoom is 2-4ms. But when I zoom out, it jumps to ~350ms for some zoom levels, and stays at 2-4ms for others - consistently, as if there were some cursed zoom levels.
float m_zoomFactor; // 1 = no zoom, <1 = zoom out
// rendering optimization
float m_lastFontSize;
int m_lastFontSizeInPixels;
const float fontSize = 75 * m_zoomFactor; // 75 virtual pixels = 2.5% window height
const int fontSizeInPixels = toPixels(fontSize);
if (fontSize != m_lastFontSize || fontSizeInPixels != m_lastFontSizeInPixels) {
m_lastFontSize = fontSize;
m_lastFontSizeInPixels = fontSizeInPixels;
// calculate text metrics... (slow due to proportional font)
}
// render visible text... (fast)
Can you spot the issue in this perfectly-legal code?
<spoiler>
The culprit is fontSize != m_lastFontSize.
While optimizing, Emscripten turns this into 75 * m_zoomFactor != m_lastFontSize, where the left-hand side is double precision (JavaScript) and the RHS is single precision (read from Float32Array). For some values of m_zoomFactor, this condition will always evaluate to true.
Emscripten has a build option PRECISE_F32 that avoid such cases by sprinkling Math.fround() everywhere, but that has performance impact so it's disabled by default. Fortunately, I don't use the above practice a lot, so I can simply fix all relevant cases by adding volatile.
</spoiler>