Memory allocation issue in Haxe using Enum as Map key type

193 Views Asked by At

I follow a 2D GPU library and saw an issue someone was having with memory allocation. An Array<Map> of enums is called every frame via setBlendMode, ultimately calling Haxe's Type.enumParameters each time.

class GBlendModeFunc
{
    private static var blendFactors:Array<Map<GBlendMode,Array<Context3DBlendFactor>>> = [
        [
            GBlendMode.NONE => [Context3DBlendFactor.ONE, Context3DBlendFactor.ZERO],
            GBlendMode.NORMAL => [Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA],
            GBlendMode.ADD => [Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.DESTINATION_ALPHA],
            GBlendMode.MULTIPLY => [Context3DBlendFactor.DESTINATION_COLOR, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA],
            GBlendMode.SCREEN => [Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE],
            GBlendMode.ERASE => [Context3DBlendFactor.ZERO, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA],
        ],
        [
            GBlendMode.NONE => [Context3DBlendFactor.ONE, Context3DBlendFactor.ZERO],
            GBlendMode.NORMAL => [Context3DBlendFactor.ONE, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA],
            GBlendMode.ADD => [Context3DBlendFactor.ONE, Context3DBlendFactor.ONE],
            GBlendMode.MULTIPLY => [Context3DBlendFactor.DESTINATION_COLOR, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA],
            GBlendMode.SCREEN => [Context3DBlendFactor.ONE, Context3DBlendFactor.ONE_MINUS_SOURCE_COLOR],
            GBlendMode.ERASE => [Context3DBlendFactor.ZERO, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA],
        ]
    ];
    
    static public function setBlendMode(p_context:Context3D, p_mode:GBlendMode, p_premultiplied:Bool):Void {
        var p:Int = (p_premultiplied) ? 1 : 0;
        p_context.setBlendFactors(blendFactors[p][p_mode][0], blendFactors[p][p_mode][1]);
    }
}

The issue here is that Type.enumParameters creates a new Array each time it checks the values of enum array from setBlendMode, quickly adding tens of thousands of variables that trigger GC frequently.

I'm not familiar with best Haxe practices and not sure how to reorganize. Is there a more performant way to store the enums that won't create an allocation issue?

Edit: The GBlendMode enums cannot be converted to abstract enums because it breaks other functions.

Edit 2: A solution was proposed: https://github.com/pshtif/Genome2D-ContextFlash/issues/17

1

There are 1 best solutions below

2
Jeff Ward On

I see this looks like Genome2D code.

But I don't see any code for the GBlendMode enum - and this whole thing hinges on that code. If enum GBlendMode is a normal enum, then at runtime they're arrays. The map getter function has to call Type.enumParameters to compare the keys -- I screen-shot a nodejs callstack to prove this to myself:

enter image description here

However, if GBlendMode is an abstract enum over String, like this:

enum abstract GBlendMode(String) {
  var NONE;
  var NORMAL;
  var ADD;
  var MULTIPLY;
  var SCREEN;
  var ERASE;
}

Then the keys are simple strings, and there is no enum comparison, and there are no intermediate arrays created.