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
I see this looks like Genome2D code.
But I don't see any code for the
GBlendModeenum - and this whole thing hinges on that code. Ifenum GBlendModeis a normal enum, then at runtime they're arrays. The map getter function has to callType.enumParametersto compare the keys -- I screen-shot a nodejs callstack to prove this to myself:However, if
GBlendModeis an abstract enum overString, like this:Then the keys are simple strings, and there is no enum comparison, and there are no intermediate arrays created.