A method that can be used to easily control the viewport pixel size is Viewport's setsizeoverride method. You can use it to control the root viewport size without needing a special scene hierarchy.
For example, to make sure that the viewport doesn't scale anything, setsizeoverride to the same as OS.getwindowsize()
# maybe in an autoload/singleton but in a scene script should also work
get_viewport().connect("size_changed", self, "window_resize")
Use this with Stretch mode 2d and Aspect ignore.
The size you send to setsizeoverride controls how many pixels the viewport takes from the source world_2d. In this case we set the number of pixels width/height that the viewport takes to be the same as the size of the window. Result is that no scaling/stretching occurs.
You will need to adjust the viewport's globalcanvastransform so it is centered correctly on your content.
To do x2, x3 scaling if the window size is large enough, then just check the window size from getwindowsize(). If it is large enough modify the size sent to setsizeoverride. (Eg. if it is >= 2x the size, then you can give setsizeoverride half of the window size.)
For your scenes, make sure your actual content is in the middle, and then surround it with whatever you want to show on the edges.