diff --git a/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java b/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java
index adff79812..40354f9d2 100644
--- a/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java
+++ b/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java
@@ -121,12 +121,12 @@ import org.openstreetmap.josm.gui.layer.imagery.ZoomToNativeLevelAction;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.HiDPISupport;
 import org.openstreetmap.josm.tools.HttpClient;
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.MemoryManager;
 import org.openstreetmap.josm.tools.MemoryManager.MemoryHandle;
 import org.openstreetmap.josm.tools.MemoryManager.NotEnoughMemoryException;
-import org.openstreetmap.josm.tools.PlatformManager;
 import org.openstreetmap.josm.tools.Utils;
 import org.openstreetmap.josm.tools.bugreport.BugReport;
 
@@ -168,11 +168,20 @@ implements ImageObserver, TileLoaderListener, ZoomChangeListener, FilterChangeLi
     private final AttributionSupport attribution = new AttributionSupport();
 
     /**
-     * Offset between calculated zoom level and zoom level used to download and show tiles. Negative values will result in
-     * lower resolution of imagery useful in "retina" displays, positive values will result in higher resolution
+     * Offset between calculated zoom level, and zoom level used to download and show tiles. Negative values will result in
+     * lower resolution of imagery, positive values will result in higher resolution useful in "Retina" displays
      */
     public static final IntegerProperty ZOOM_OFFSET = new IntegerProperty(PREFERENCE_PREFIX + ".zoom_offset",
-            PlatformManager.getPlatform().isHighDpiDisplay() ? 2 : 0);
+            getDefaultZoomOffset(HiDPISupport.getHiDPIScale()));
+
+    /**
+     * Calculate the zoom offset for best display results, given the scaling factor of the screen (e.g. 2 for Retina displays)
+     * @param scalingFactor scaling factor of the screen
+     * @return suggested zoom offset
+     */
+    static int getDefaultZoomOffset(double scalingFactor) {
+        return (int) Math.ceil(Math.log(scalingFactor) / (Math.log(2.0) / 2.0));  // calculate logarithm on base sqrt(2), and round up
+    }
 
     /*
      *  use MemoryTileCache instead of tileLoader JCS cache, as tileLoader caches only content (byte[] of image)
diff --git a/src/org/openstreetmap/josm/tools/HiDPISupport.java b/src/org/openstreetmap/josm/tools/HiDPISupport.java
index f54e3ff2e..368823e9c 100644
--- a/src/org/openstreetmap/josm/tools/HiDPISupport.java
+++ b/src/org/openstreetmap/josm/tools/HiDPISupport.java
@@ -169,7 +169,7 @@ public final class HiDPISupport {
      * only take the default screen device into account.
      * @return the GUI scale for HiDPI mode, a value of 1.0 means standard mode.
      */
-    static double getHiDPIScale() {
+    public static double getHiDPIScale() {
         if (GraphicsEnvironment.isHeadless())
             return 1.0;
         GraphicsConfiguration gc = GraphicsEnvironment
diff --git a/src/org/openstreetmap/josm/tools/PlatformHook.java b/src/org/openstreetmap/josm/tools/PlatformHook.java
index abd99e213..19cffad3a 100644
--- a/src/org/openstreetmap/josm/tools/PlatformHook.java
+++ b/src/org/openstreetmap/josm/tools/PlatformHook.java
@@ -136,18 +136,6 @@ public interface PlatformHook {
                 GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().isFullScreenSupported();
     }
 
-    /**
-     * Determines if the default screen is a high-dpi device such as a mac Retina display.
-     * @return {@code true} if the default screen is a high-dpi device such as a mac Retina display
-     * @since 15918
-     */
-    default boolean isHighDpiDisplay() {
-        // https://stackoverflow.com/a/49770313
-        return !GraphicsEnvironment.isHeadless() &&
-                !GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration()
-                .getDefaultTransform().isIdentity();
-    }
-
     /**
      * Renames a file.
      * @param from Source file
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayerTest.java b/test/unit/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayerTest.java
index 9ba10b5bd..1a724a8f5 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayerTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayerTest.java
@@ -204,4 +204,18 @@ public class AbstractTileSourceLayerTest {
     public void testTileSourceLayerPopup() {
         assertNotNull(testLayer.new TileSourceLayerPopup(100, 100));
     }
+
+    /**
+     * Test {@link AbstractTileSourceLayer#getDefaultZoomOffset}
+     */
+    @Test
+    public void testGetDefaultZoomOffset() {
+        assertEquals(-1, AbstractTileSourceLayer.getDefaultZoomOffset(0.7));
+        assertEquals(0, AbstractTileSourceLayer.getDefaultZoomOffset(0.8));
+        assertEquals(0, AbstractTileSourceLayer.getDefaultZoomOffset(1.0));
+        assertEquals(1, AbstractTileSourceLayer.getDefaultZoomOffset(1.25));
+        assertEquals(2, AbstractTileSourceLayer.getDefaultZoomOffset(1.5));
+        assertEquals(2, AbstractTileSourceLayer.getDefaultZoomOffset(2.0));
+        assertEquals(4, AbstractTileSourceLayer.getDefaultZoomOffset(3.0));
+    }
 }
