How to make BitmapFilter work in OpenFL 6 on native targets

I’m apologising in advance if this was asked before, but with recent changes my custom shader filters extended from BitmapFilter stopped working. Previously, this was all I had to do to get it work:

var customFilter = new CustomFilter();
bitmap.filters = [customFilter];

Currently when I do it, the shader code is not executing, even __initShader() method is not executing. I tried changing __numShaderPasses but it didn’t make shader execute.

When I add shader to Bitmap directly, i. e.:

bitmap.shader = new CustomShader();

the shader executes correctly, but it is a multipass shader and I need to pass information to shader about what pass it is currently in, which I cannot do this way (or haven’t found a way to do it yet). I was doing this in the __initShader() method previously:

private override function __initShader (renderSession:RenderSession, pass:Int):Shader {
    __customShader.data.pass.value = [pass];
    return  __customShader;
}

I had hoped that .shader would provide a suitable workaround, but it seems we’ll have to do more. The way we used framebuffers before for shader filters was not suitable for mobile targets, and requires a rework.

I’ve opened an issue here: https://github.com/openfl/openfl/issues/1704

Well, using .shader directly would be fine with me, but I’m not sure if multipass shaders work at all right now. I noticed that Shader class has __numPasses property, but changing this doesn’t seem to do anything (I didn’t investigated thoroughly how shaders are currently executed).

If shader executed __numPasses and there was some way to know in shader code which pass we are currently in (for example I used uniform float uPass, float due int to float conversion slowdown in some graphic cards), it would solve my problems. But I’m not too sure about framebuffer object management in multipass scenario or what is a best way to do this to be mobile friendly.

Interesting, I did not know about int to float conversion being costly on some graphics cards

I think that might be what happened with our framebuffers. I heard that you need to not use a framebuffer again in the same frame, or ideally not even in the next frame, due to the way buffering works on the graphics card. We used the same framebuffer again heavily, which might be why mobile performance was shipwrecked

Well, yes and sadly, yes.

GPUs are optimised for floating point arithmetics, so almost everything integer based will probably be slower. I’m not sure if checking against integer in if statement is slower than checking against float, but I used float just in case.

As far as I know, it’s generally not good idea to read and write to same buffer in one shader pass, but in some algorithms (like with what I’m dealing right now) you have no other choice, so I think there definitely should be an option to do that. It probably shouldn’t be used on standard “Flash” filters because of slowdowns on mobile, but for some special cases it is a reasonable tradeoff.

Just to be certain – is there currently any way at all to apply two passes of the same shader or two different shaders on one object? Second solution would probably work better for me anyway.

We need to re-evaluate support for framebuffer/GL shader-based filters. I think if we use a new framebuffer for each texture (instead of reusing the same framebuffers) it might solve some of the bottlenecks we hit before

2 Likes