fl_text_extents() should be /really/ accurate. Like precise to the pixel. You'll get different sizes even on the vertical axis, depending on if the text has caps vs lowercase and if there's characters with descenders or not. It gives you literally the drawing extents of the text. Font Antialiasing /might/ add a fuzz factor to the calculations, perhaps +/- 1 pixel at each edge, not sure.
You probably should leave some margin all the way around anyway, otherwise your button's borders will be tangent to the text. I'd suggest adding at least 3 pixels all the way around minimum, so use w+6 and h+6. Keep in mind the button's borders need room too, so allow for that.