Jchabin
Jchabin

Reputation: 103

My SVG Filter is running extremely slowly

I have the following SVG filter:

<svg style="visibility: hidden; height: 0; width: 0;">
    <filter id="rgbShift">
        <feOffset in="SourceGraphic" dx="1" dy="-1" result="text1" />
        <feFlood flood-color="#FF0000" result="redColor" />
        <feComposite in="redColor" in2="text1" operator="arithmetic" k1="1" result="red" />
        <feOffset in="SourceGraphic" dx="-1" dy="2" result="text2" />
        <feFlood flood-color="#00FF00" result="greenColor" />
        <feComposite in="greenColor" in2="text2" operator="arithmetic" k1="1" result="green" />
        <feOffset in="SourceGraphic" dx="-2" dy="1" result="text3" />
        <feFlood flood-color="#0000FF" result="blueColor" />
        <feComposite in="blueColor" in2="text3" operator="arithmetic" k1="1" result="blue" />
        <feComposite in="red" in2="green" operator="lighter" result="rb" />
        <feComposite in="rb" in2="blue" operator="lighter" />
    </filter>
</svg>

This filter is applied to my menu screen in a game I am working on. I want to apply the same filter to the game itself, but it runs very slowly, probably because elements are almost constantly moving on the page. Is there a way to make my filter run faster?

Upvotes: 0

Views: 1359

Answers (2)

Michael Mullany
Michael Mullany

Reputation: 31715

I do not know if it's the cause of your performance problems, but feComposite is a slow operation and you have many mistakes in your syntax.

  • In SVG 1.1 feComposite has no "lighter" operator. That was added in the Filters 1.0 spec and is not supported cross-browser yet. You may want to go with feComposite operator="arithmetic" k2="1" k3="1" which I believe is equivalent.
  • It's usually a better idea to use feBlend/multiply than feComposite/arithmetic, it seems to be much faster.

A corrected implementation of what I think you wanted with your original filter would be as follows:

<filter id="rgbShift">
    <feOffset in="SourceGraphic" dx="1" dy="-1" result="text1" />
    <feFlood flood-color="#FF0000" result="redColor" />
    <feBlend in="text1" in2="redColor" mode="multiply" result="red"/>
    <feOffset in="SourceGraphic" dx="-1" dy="2" result="text2" />
    <feFlood flood-color="#00FF00" result="greenColor" />
    <feBlend in="text2" in2="greenColor" mode="multiply" result="green"/>
    <feOffset in="SourceGraphic" dx="-2" dy="1" result="text3" />
    <feFlood flood-color="#0000FF" result="blueColor" />
    <feBlend in="text3" in2="blueColor" mode="multiply" result="blue"/>
    <feComposite in="red" in2="green" operator="arithmetic" k2="1" k3="1" result="rb" />
    <feComposite in="rb" in2="blue" operator="arithmetic" k2="1" k3="1"/>
</filter>

Upvotes: 1

ccprog
ccprog

Reputation: 21821

While I have no formal results, testing it on a single jpg picture in Inkscape gives me the impression that the following filter is perceptably faster, while being mathematically identical AFAIK:

<filter id="rgbShift">
    <feOffset in="SourceGraphic" dx="1" dy="-1" />
    <feComponentTransfer result="red">
        <feFuncG type="discrete" tableValues="0" />
        <feFuncB type="discrete" tableValues="0" />
    </feComponentTransfer>
    <feOffset in="SourceGraphic" dx="-1" dy="2" />
    <feComponentTransfer result="green">
        <feFuncR type="discrete" tableValues="0" />
        <feFuncB type="discrete" tableValues="0" />
    </feComponentTransfer>
    <feOffset in="SourceGraphic" dx="-2" dy="1" />
    <feComponentTransfer result="blue">
        <feFuncR type="discrete" tableValues="0" />
        <feFuncG type="discrete" tableValues="0" />
    </feComponentTransfer>
    <feComposite in="red" in2="green" operator="arithmetic" k2="1" k3="1" result="rb" />
    <feComposite in="rb" in2="blue" operator="arithmetic" k2="1" k3="1" />
</filter>

Whether that is enough, I don't know. The following measures might help avoiding time-critical operations (i. e. recomputing the filter for every frame):

  • Do not apply the filter to animated elements.
  • Do not apply the filter to elements so that their filter effects region (the bounding box of the filtered element plus, as default, 10% in every direction) overlaps the bounding box of animated elements. Whether they are above or below does not matter.

Upvotes: 4

Related Questions