hajimehoshi / ebiten

Ebitengine - A dead simple 2D game engine for Go
https://ebitengine.org
Apache License 2.0
11.05k stars 662 forks source link

Performance problem with 'terraformer' #509

Closed hajimehoshi closed 6 years ago

hajimehoshi commented 6 years ago

Tommaso Visconti at Gophers Slack:

I began my adventure with Go writing a little simcity-style game and my 1st choice was Ebiten, but I immediately had performance issues. I tried to optimize it without much luck, with few elements it immediately dropped to veeeeery low fps (like 4fps). Then I moved to go-sdl2 and it performed immediately way better (llike 400fps) @hajimehoshi here's is just before we decided to switch to go-sdl2: https://gitlab.com/i-tre-brutti/terraformer/tree/3148c203451cbb6a638c89a3546dcf3cdc7d1975

hajimehoshi commented 6 years ago

I got about 30 FPS on my machine. Not too bad.

hajimehoshi commented 6 years ago

The simplest case:

package main

import (
        "fmt"

        "github.com/hajimehoshi/ebiten"
        "github.com/hajimehoshi/ebiten/ebitenutil"
)

func update(screen *ebiten.Image) error {
        ebitenutil.DebugPrint(screen, fmt.Sprintf("%0.2f", ebiten.CurrentFPS()))
        return nil
}

func main() {
        if err := ebiten.Run(update, 2000, 2000, 1, "test"); err != nil {
                panic(err)
        }
}

This is about 20-25 FPS on my MacBook Pro.

tommyblue commented 6 years ago

@hajimehoshi it runs at 60fps both on the mac (2560 x 1600) and the external monitor (2560x1440, 60Hz)

hajimehoshi commented 6 years ago

Thanks, Your mac is Retina display, right?

tommyblue commented 6 years ago

yes, but it happened also on a Dell

hajimehoshi commented 6 years ago

My MacBook Pro is in mid 2014, so I guess that's why the performance is bad :-)

Now the FPS is 30-40 with a very simple optimization (the above simplest case). I'll do further more.

hajimehoshi commented 6 years ago

Now the FPS is over 50, but this is not enough.

What I learned is:

hajimehoshi commented 6 years ago

Remove glClear calls, that was blocking everything. Now the FPS is 60 on my MacBook Pro (MatrixSize=20 and BaseNumber = 64 in common.go)!

hajimehoshi commented 6 years ago

Next challenge is to make the game 60FPS in

MatrixSize = 30
BaseNumber = 32
hajimehoshi commented 6 years ago

Found that in "terraformer", two image sources are used one after the other. In the below dump, the first column is the image address and second column is the number of count how many times it is used at DrawImage:

0xc4200421c0 11
0xc420042380 1
0xc4200421c0 9
0xc420042380 1
0xc4200421c0 7
0xc420042380 1
0xc4200421c0 12
0xc420042380 1
0xc4200421c0 11
0xc420042380 1
0xc4200421c0 14
0xc420042380 1
0xc4200421c0 10
0xc420042380 1
0xc4200421c0 6
0xc420042380 1
0xc4200421c0 16
0xc420042380 1
0xc4200421c0 12
0xc420042380 1
0xc4200421c0 12
0xc420042380 1
0xc4200421c0 7
0xc420042380 1
0xc4200421c0 13
0xc420042380 1
0xc4200421c0 9
0xc420042380 1
0xc4200421c0 13
...

@tommyblue As the wiki says, your game would run much faster to reorder DrawImage calls. Without such change, probably Ebiten cannot run your game faster.

I'm thinking to introduce "texture atlas utility" (#91) or "automatic texture atlas" feature, but not determined yet.

tommyblue commented 6 years ago

@hajimehoshi thanks for the debug. What is not clear to me, as a very inexperienced go and game-dev user, is what we were doing wrong and why moving from ebiten to go-sdl2, with quite unchanged code structure, the performances were so different. I mean, I'm not saying ebiten is bad and go-sdl2 is good, but if we did something wrong, we were doing it without knowing so maybe you could arrange a wiki page like: "How to structure your project from 0 and have good performances with Ebiten" or create a repo with a project skeleton that unskilled users can clone/fork as a start point and profit! 😃

hajimehoshi commented 6 years ago

Thank you for your feedback. I agree such skeleton project would be useful. On the other hand, Ebiten is a kind of low level lib and I didn't determine a good project "skeleton" on purpose.

At least in your case, "automatic texture atlas" "shared texture" (#514) where images created via NewImageFromImage share a same texture would solve the problem and this should be useful in most games. In the ideal world, Ebiten should run any game codes quickly, and actually it looks like SDL2 works very well without changing the structure.

hajimehoshi commented 6 years ago

@tommyblue Out of curiosity, how do your draw images with SDL2? Software rendering or OpenGL with SDL2? If I understand correctly, SDL doesn't offer GPU rendering by default.

tommyblue commented 6 years ago

well, afaik, it does. See SDL_RENDERER_ACCELERATED here: https://wiki.libsdl.org/SDL_CreateRenderer

we do it here: https://gitlab.com/i-tre-brutti/terraformer/blob/master/loop/loop.go#L112

hajimehoshi commented 6 years ago

I've implemented 'shared texture', which creates texture atlas automatically. Now Ebiten can run 'terraformer' with 60 FPS without code change :-)

tommyblue commented 6 years ago

wonderful!