diff --git a/examples/highdpi/main.go b/examples/highdpi/main.go index 23f653593..83993b1fa 100644 --- a/examples/highdpi/main.go +++ b/examples/highdpi/main.go @@ -15,9 +15,11 @@ package main import ( + "flag" "fmt" _ "image/jpeg" "log" + "runtime" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/ebitenutil" @@ -93,7 +95,16 @@ func (g *Game) Draw(screen *ebiten.Image) { op.Filter = ebiten.FilterLinear screen.DrawImage(g.highDPIImage, op) - ebitenutil.DebugPrint(screen, fmt.Sprintf("(Init) Device Scale Ratio: %0.2f", scale)) + msg := fmt.Sprintf("Device Scale Ratio: %0.2f", scale) + if runtime.GOOS == "js" { + if !*flagDisable { + msg += "\nHiDPI rendering is enabled. You can disable HiDPI by -disable flag." + } else { + msg += "\nHiDPI rendering is disabled." + } + } + // TODO: The texts might be too small. Improve legibility. + ebitenutil.DebugPrint(screen, msg) } func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) { @@ -103,10 +114,16 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) { return int(float64(outsideWidth) * s), int(float64(outsideHeight) * s) } +var flagDisable = flag.Bool("disable", false, "disables HiDPI rendering (only on browsers)") + func main() { + flag.Parse() + ebiten.SetWindowSize(640, 480) ebiten.SetWindowTitle("High DPI (Ebitengine Demo)") - if err := ebiten.RunGame(NewGame()); err != nil { + op := &ebiten.RunGameOptions{} + op.DisableHiDPI = *flagDisable + if err := ebiten.RunGameWithOptions(NewGame(), op); err != nil { log.Fatal(err) } } diff --git a/internal/ui/ui.go b/internal/ui/ui.go index c04d1c859..b8f3991d8 100644 --- a/internal/ui/ui.go +++ b/internal/ui/ui.go @@ -175,6 +175,7 @@ type RunOptions struct { ScreenTransparent bool SkipTaskbar bool SingleThread bool + DisableHiDPI bool X11ClassName string X11InstanceName string } diff --git a/internal/ui/ui_js.go b/internal/ui/ui_js.go index f9b4a6f2a..a8d58fa8f 100644 --- a/internal/ui/ui_js.go +++ b/internal/ui/ui_js.go @@ -96,6 +96,7 @@ type userInterfaceImpl struct { cursorShape CursorShape onceUpdateCalled bool lastCaptureExitTime time.Time + hiDPIEnabled bool context *context inputState InputState @@ -465,6 +466,7 @@ func (u *UserInterface) init() error { runnableOnUnfocused: true, savedCursorX: math.NaN(), savedCursorY: math.NaN(), + hiDPIEnabled: true, } // document is undefined on node.js @@ -762,6 +764,8 @@ func (u *UserInterface) shouldFocusFirst(options *RunOptions) bool { func (u *UserInterface) initOnMainThread(options *RunOptions) error { u.setRunning(true) + u.hiDPIEnabled = !options.DisableHiDPI + if u.shouldFocusFirst(options) { canvas.Call("focus") } @@ -815,6 +819,10 @@ func (m *Monitor) Name() string { } func (m *Monitor) DeviceScaleFactor() float64 { + if !theUI.hiDPIEnabled { + return 1 + } + if m.deviceScaleFactor != 0 { return m.deviceScaleFactor } diff --git a/run.go b/run.go index 2291562e5..4b75970e8 100644 --- a/run.go +++ b/run.go @@ -274,6 +274,15 @@ type RunGameOptions struct { // The default (zero) value is false, which means that the single thread mode is disabled. SingleThread bool + // DisableHiDPI indicates whether the rendering for HiDPI is disabled or not. + // If HiDPI is disabled, the device scale factor is always 1 i.e. Monitor's DeviceScaleFactor always returns 1. + // This is useful to get a better performance on HiDPI displays, in the expense of rendering quality. + // + // DisableHiDPI is available only on browsers. + // + // The default (zero) value is false, which means that HiDPI is enabled. + DisableHiDPI bool + // X11DisplayName is a class name in the ICCCM WM_CLASS window property. X11ClassName string @@ -703,6 +712,7 @@ func toUIRunOptions(options *RunGameOptions) *ui.RunOptions { ScreenTransparent: options.ScreenTransparent, SkipTaskbar: options.SkipTaskbar, SingleThread: options.SingleThread, + DisableHiDPI: options.DisableHiDPI, X11ClassName: options.X11ClassName, X11InstanceName: options.X11InstanceName, }