[HTML5] Starling 2.2.1 Update vs OpenFL masks

Hey guys,

I’ve been forced by dragonbones skeletal animation to update Starling from old 1.8 to 2.2, because meshes in dragonbones are supported only in Starling 2+. So i’ve gone through all the struggle to change a lot of things to match new structures ex. implementation of custom FragmentFilters and I’ve noticed that my OpenFL sprite masks disappeared all at once. It looks like Starling renders on top of these making them invisible but I can still easily click on each element of a masked clip (while it is invisible)(buttonMode shows different cursor) and it can be moved around or be interacted with in any other way.

I currently cannot provide any code sample to recreate this but maybe someone has encountered a similar issue and found a nice solution?

Cheers,
Łukasz

1 Like

Also, I’m not 100% sure but out of the box, performance-wise it is slower a lot. Had 60fps, stable with 5-10 bones animation before (1.8.13), now 35fps right from the start, down to 15-20 while animating (2.2.1). I believe I’ve made some mistake and it is affecting the performance, so if anyone had similar issue, please share some solution.

How much of your content is in OpenFL (such as the sprite masks), and how much is in Starling?

Did you upgrade your OpenFL version in the process of upgrading Starling?

I’ve got OpenFL upgraded before upgrading Starling so everything works perfectly fine on OpenFL 7.1.2, Lime 6.2.0, Starling 1.8.13, Dragonbones 5.0.0. I’ve just updated Starling to 2.2.1. Most of the content is OpenFL content - I’m using Starling for one dragonbones animation (around 5-10 bones) and for one simple Image with custom FragmentFilter (custom AGAL shaders). Image is around 800x600 (static textures, no heavy calculations besides those done in fragment shader).

In 1.8.13 I get around 60FPS almost constant while in 2.2.1 it gets immediately to 35FPS with animation hidden (I’ve even disabled all other things) while dropping to 15-20FPS while animating. I’m working on late 2012 Mac Mini with i5 and testing on Chrome 64 but I believe there is no issue with any of these but the library itself.

Since I have almost no spare time now, I’ll try to do some comprehensive samples during the upcoming weekend and if the results are similar I’ll post some issues on Starling github. I’ve just wanted to know whether someone has similar issue to mine after upgrading - if nobody, then I’m doing something wrong.

I’ve just tested 2.2.1 with both example Dragon animation and my own animation and it works well. I’m looking for some more clues and will share the results of my investigation with you as soon as I come to any more precise conclusions.

So Starling (without OpenFL content) works, and OpenFL works, but the combination of the two (with the later version of Starling) causes this issue? It may be a conflict in the GL context, as both Stage3D and the OpenFL renderer share the same context right now

Do you have a way I could reproduce it?

I will try to provide a comprehensive sample within few days (probably in the upcoming weekend).

1 Like

I struggle to recreate this bug in a test application even though I’ve added everything as I do in my real one. I need more time to provide the sample I’ve promised delivering. I’m working on it.

I have encountered this problem.

Any more informations on that? Have you solved it or at least got any clue what caused the problem?

No, I didn’t solve it, but I found it to happen in the FragmentFilter, especially when moving the scene (this may happen in the larger display object in the FragmentFilter area),currently I try to use MeshStyle to solve it.

My MeshSytle experiment was successful and the efficiency increased to 60FPS, which means that the filter was unexpectedly occupied.

AGAL code:

    package zygame.filter;

import starling.styles.MeshStyle;
import starling.rendering.MeshEffect;
import starling.rendering.RenderState;
import openfl.display3D.Context3D;
import openfl.display3D.Context3DProgramType;
import starling.rendering.MeshEffect;
import starling.rendering.Program;
import starling.rendering.VertexDataFormat;
import openfl.Vector;

class SetColorStyle extends MeshStyle
{

    private var _color:UInt;

    public function new(color:UInt)
	{
        super();
        _color = color;
    }

    public function getColor():UInt
    {
        return _color;
    }

    override public function createEffect():MeshEffect
    {
        return new SetColorEffect(_color);
    }

    override public function updateEffect(effect:MeshEffect, state:RenderState):Void
    {
        cast(effect,SetColorEffect).setColor(_color);
        super.updateEffect(effect,state);
    }

    override public function copyFrom(meshStyle:MeshStyle):Void
    {
        if(Std.is(meshStyle,SetColorStyle)) 
        {
            var colorStyle:SetColorStyle = cast(meshStyle,SetColorStyle);
            this._color = colorStyle.getColor();
        }
        super.copyFrom(meshStyle);
    }
        
    
} 

class SetColorEffect extends MeshEffect {
    
	private var ver:Vector<Float>;

    public function new(color:UInt)
    {
        super();
        ver = new Vector<Float>([0,0,0,1]);
		setColor(color);
    }

    public function setColor(rgb:UInt):Void
	{
		var r:Int = rgb>>16;
		var g:Int = (rgb>>8)&0xff; 
		var b:Int = rgb&0xff;
		ver[0] = r/255;
		ver[1] = g/255;
		ver[2] = b/255;
	}

    override public function createProgram():Program
    {
        // TODO
		var vertexShader:String =  "m44 op, va0, vc0 \n" + // 4x4 matrix transform to output clip-space
				"mov v0, va1      \n" + // pass texture coordinates to fragment program
				"mul v1, va2, vc4 \n";  // multiply alpha (vc4) with color (va2), pass to fp;

		var fragmentShader:String =
			"tex ft0, v0, fs0 <2d, repeat> \n" +
			"mul ft1, fc0, ft0.wwww \n"+
			"mov oc, ft1";
		
		return Program.fromSource(vertexShader, fragmentShader);
    }

    override public function beforeDraw(context:Context3D):Void
	{
		super.beforeDraw(context);
		context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT,0, ver);
	}

}

If the above code is placed on the filter, the performance will become extremely low.

That’s a great hint. I’ll try it out soon.

:smiley:If you can solve the filter, then it is really great.

I can finally get back to this topic and this issue. I’ve managed to upgrade Starling to 2.4 and I guess performance issues are now gone or at least performance has increased so the difference is barely noticeable. I need to stick to Starling 2.0 because of Dragonbones meshes. Problem with masks still exists and I’ve got a simple example of how I’ve achieved that. Whenever I fall back to 1.8.13 or disable Starling completely it works. Sadly, I cannot replace masks with any substitute because nothing provides an effect I want to achieve. I’m going to try out changing things around to maybe provide some more informations on this issue.

Starling 2.4.0 (or 2.2.1, does not matter for this issue)
OpenFL 8.3.0
Lime 6.4.0

package ;

import openfl.display.MovieClip;
import openfl.geom.Rectangle;
import openfl.system.Capabilities;
import openfl.events.Event;
import openfl.display.Sprite;
import openfl.display3D.Context3DRenderMode;
import starling.core.Starling;

class Scene extends Sprite {
    public static inline var SCENE_WIDTH:Int = 200;
    public static inline var SCENE_HEIGHT:Int = 200;

    private var _starling(null, null):Starling;

    private var _masked_clip(null, null):MovieClip;
    private var _mask(null, null):Sprite;

    public function new() {
        super();

        this.addEventListener(Event.ADDED_TO_STAGE, this.onContextCreated);
    }

    private function onContextCreated(e:Event):Void {
        this.removeEventListener(Event.ADDED_TO_STAGE, this.onContextCreated);

        this._starling = new Starling(StarlingMain, this.stage, new Rectangle(0.0, 0.0, Scene.SCENE_WIDTH, Scene.SCENE_HEIGHT), this.stage.stage3Ds.get(0), Context3DRenderMode.AUTO, 'auto');
        this._starling.enableErrorChecking = Capabilities.isDebugger;
        this._starling.showStats = true;
        this._starling.addEventListener(starling.events.Event.ROOT_CREATED, this.onRootCreated);
        this._starling.start();
    }

    private function onRootCreated(e:Event):Void {
        this._starling.removeEventListener(starling.events.Event.ROOT_CREATED, this.onRootCreated);

        this._mask = new Sprite();
        this._mask.graphics.lineStyle(1, 0xFFFFFF);
        this._mask.graphics.beginFill(0x000000, 1.0);
        this._mask.graphics.drawRect(0.0, 0.0, 50.0, 50.0);
        this._mask.graphics.endFill();

        this.addChild(this._masked_clip = new MaskAsset());

        this._masked_clip.x = (Scene.SCENE_WIDTH - this._masked_clip.width) * 0.5;
        this._masked_clip.y = (Scene.SCENE_HEIGHT - this._masked_clip.height) * 0.5;

        this.addChild(this._mask);
        this._mask.x = this._masked_clip.x + 25.0;
        this._mask.y = this._masked_clip.y + 25.0;

//      TODO: This line causes both Mask and Masked Clip to completely disappear
        this._masked_clip.mask = this._mask;
    }
}

class StarlingMain extends starling.display.Sprite {

    public function new() {
        super();
    }
}

and my project.xml file:

<?xml version="1.0" encoding="utf-8"?>
<project>

    <meta title="Mask" package="com.issue.test" version="1.0.0" company="None"/>
    <app main="Scene" path="Export" file="Scene"/>

    <source path="Source"/>

    <haxelib name="openfl"/>
    <haxelib name="starling"/>
    <haxelib name="dragonbones"/>
    <haxelib name="actuate"/>
    <haxelib name="swf"/>

    <window width="200" height="200" fps="60" hardware="true" allow-shaders="true" require-shaders="true" resizable="false"/>

    <assets path="Assets" rename="assets" include="*"/>

    <library path="Assets/mask.swf" preload="true" generate="true"/>
</project>

With TODO marked line not commented out:
30

With TODO marked line commented out
39

I cannot upload SWF file but I’ve used Adobe Animate CC to create that simple MaskAsset (4x Text Fields, 4x simple Shapes).

I’d be glad if anyone could assist me on this matter.

Thank for the example code, OpenFL masks and Starling conflict with each other, since they both use the same stencil buffer. Perhaps we need to start doing Stage3D in its own framebuffer, so we can guard against things like this.

“we need to start doing Stage3D in its own framebuffer”

I agree :wink:

Maybe this will fix the problem I reported yesterday: here

For now, I’ve managed to move Dragonbones from using Starling to using OpenFL factories and armatures and it works perfect (with the meshes). With Starling I’m sticking to 1.8.13 for now.