Gamua / Starling-Framework

The Cross Platform Game Engine
http://www.starling-framework.org
Other
2.84k stars 819 forks source link

using DistanceFieldStyle = draw calls amount explosion #915

Closed Incubatio closed 7 years ago

Incubatio commented 7 years ago

Description:

I updated my game and added DistanceFieldStyle and I am really happy about the features added with that upgrade.

However I met a rather important issue: my game went from 11 to 99 draw calls.

Simple experiment:

I made a simple starling project with:

case1: textfield.style = null, textfield.batchable = false, 10 draw calls https://puu.sh/rHvv1/4465dbac6c.png

case2: textfield.style = null, textfield.batchable = true, 1 draw call, works as expected. https://puu.sh/rHv1a/e145ca5d38.png

case3: textfield.style = new DistanceFieldStyle(), textfield.batchable = true, 10 draw calls. https://puu.sh/rHv9d/5ff6983218.png

Note: without an image in each sprite, textfield with distanceField does batch correctly.

PrimaryFeather commented 7 years ago

Unfortunately, that works as designed. :wink:

Only meshes with the same MeshStyle can be batched together. Your icons (naturally) use the default MeshStyle, while the text fields use the new DistanceFieldStyle. When Starling iterates over these objects, it constantly switches between those two styles, which causes a new batch for each object.

The only workaround would be to make two layers (sprites), one containing all icons, the other all text fields. Then, all the icons and all the TextFields will be batched together, and you'd have two draw calls.

That's the only way, unfortunately!

Incubatio commented 7 years ago

Fair enough, thank you for the input.

PrimaryFeather commented 7 years ago

You're welcome! Thanks for your understanding.

Incubatio commented 7 years ago

(just some afterthought and user feedback if anyone is interested in it)

Short story

I’ve considered the options of keeping distanceField everywhere in my game by adding extra layer to manage text in the game. All the implementation I can think of are adding substantial amount of work, would generate more point of failure (source of bugs), making the game a lot more hard to upgrade and maintain. Having several bitmapFont and using distanceField only for title seem the right way to go.

Long story

The problem

Take this common situation: an eye candy appearing on a popup, being itself on top of a simple UI. Those three element each have image(s) and text(s).

we could:

I won’t go into the potential solution detail, but both solution increase structural/design complexity, bring drastical restrictions, add extra draw calls. In other words, it makes adding, updating and maintaining UI a painful constant puzzle.

My solution

Before distance field update I was using a bitmapFont size 72 everywhere.

Since the update I was using a bitmapFont size 32 as scaling works really well with distanceField. It also added a variety of colour on texts and borders which is nice.

As I want to keep colours, but certainly not increase complexity of my rendering logic, my current solution involves four bitmapFont size 32. One of the bitmapFont uses distanceField and is meant for title only, so i’ll pay extra draw calls, but just for titles. The 3 other bitmapFont have the preset of colour and border I want to keep.

As a result, my rendering logic is the same, my atlas size is pretty much the same, I got my coloured text, and few extra draw calls for titles.

PrimaryFeather commented 7 years ago

Thanks a lot for your thoughts and for describing the solution you came up with!

At the moment, I think that's a very good compromise. I'm aware of the problem, and I hope to simplify this in the future, e.g. by adding a flag that would automatically sort display objects by their mesh style on rendering, instead of their position within the display list. Stay tuned!

b005t3r commented 7 years ago

A while ago we were discussing similar hypothetical scenarios which would require custom batching and if I remember correctly your answer was it should be quite easy with v2.0 and all that's needed is creating a custom MeshBatch subclass which would batch two different styles and render the batched contents at some point.

Is this possible currently? I'm asking because I still use v1.8 but hope to make the switch in a couple of days, so I'd like to know what's possible (or rather feasible) and what's not. With v1.8 I was able to create my own batching classes for such cases but those are hardly robust or convenient to use, so I hope it's made easier in v2.0.

PrimaryFeather commented 7 years ago

I think when I wrote that, I was still in the midst of developing version 2, and I originally had a different plan for custom rendering and batching. Right now, you cannot add your own batchers; instead, you write only the MeshStyle, which has a canBatch method that decides if one mesh can be batched with another one.

However, there is a BatchProcessor that oversees that, and this is a potential point where such custom logic could be included. Right now, the Painter has its usage hard-coded, but this could potentially be customized.